Réponses:
Un couplage étroit se produit lorsqu'un groupe de classes dépend fortement les unes des autres.
Ce scénario se produit lorsqu'une classe assume trop de responsabilités ou lorsqu'une préoccupation est répartie sur plusieurs classes plutôt que d'avoir sa propre classe.
Le couplage lâche est obtenu au moyen d'une conception qui favorise la responsabilité unique et la séparation des préoccupations.
Une classe à couplage lâche peut être consommée et testée indépendamment des autres classes (concrètes).
Les interfaces sont un outil puissant à utiliser pour le découplage. Les classes peuvent communiquer via des interfaces plutôt que d'autres classes concrètes, et n'importe quelle classe peut être à l'autre bout de cette communication simplement en implémentant l'interface.
Exemple de couplage serré:
class CustomerRepository
{
private readonly Database database;
public CustomerRepository(Database database)
{
this.database = database;
}
public void Add(string CustomerName)
{
database.AddRow("Customer", CustomerName);
}
}
class Database
{
public void AddRow(string Table, string Value)
{
}
}
Exemple de couplage lâche:
class CustomerRepository
{
private readonly IDatabase database;
public CustomerRepository(IDatabase database)
{
this.database = database;
}
public void Add(string CustomerName)
{
database.AddRow("Customer", CustomerName);
}
}
interface IDatabase
{
void AddRow(string Table, string Value);
}
class Database implements IDatabase
{
public void AddRow(string Table, string Value)
{
}
}
Un autre exemple ici .
Le chapeau est "légèrement couplé" au corps. Cela signifie que vous pouvez facilement retirer le chapeau sans modifier la personne / le corps. Lorsque vous pouvez le faire, vous avez un "couplage lâche". Voir ci-dessous pour l'élaboration.
Pensez à votre peau. Il est collé à votre corps. Il tient comme un gant. Mais que se passe-t-il si vous voulez changer la couleur de votre peau du blanc au vert? Pouvez-vous imaginer à quel point il serait douloureux de décoller votre peau, de la teindre, puis de la recoller, etc.? Changer de peau est difficile car elle est étroitement liée à votre corps. Vous ne pouvez tout simplement pas apporter de modifications facilement. Il faudrait repenser fondamentalement un être humain afin de rendre cela possible.
Dieu n'était pas un bon programmeur orienté objet.
Pensez maintenant à vous habiller le matin. Tu n'aimes pas le bleu? Pas de problème: vous pouvez mettre une chemise rouge à la place. Vous pouvez le faire facilement et sans effort car la chemise n'est pas vraiment connectée à votre corps de la même manière que votre peau. La chemise ne sait pas ou se soucie de quel corps elle se passe . En d'autres termes, vous pouvez changer de vêtements sans vraiment changer votre corps.
C'est le concept de base en bref.
C'est important car le logiciel change tout le temps. D'une manière générale, vous souhaitez pouvoir modifier facilement votre code, sans changer votre code. Je sais que cela ressemble à un oxymore, mais veuillez faire preuve de patience.
Exemples CSV / JSON / DB: Si quelqu'un veut sa sortie dans un fichier CSV plutôt que JSON, etc., ou si vous voulez passer de MySQL à PostGreSQL, vous devriez pouvoir effectuer ces changements extrêmement facilement dans votre code, sans avoir à réécrire toute la classe, etc. En d'autres termes, vous ne voulez pas coupler étroitement votre application avec une implémentation de base de données spécifique (par exemple Mysql) ou à une sortie particulière (par exemple des fichiers CSV). Parce que, comme c'est inévitable dans les logiciels, des changements viendront. Quand ils arrivent, c'est beaucoup plus facile si vos parties de votre code sont mal couplées.
Exemple de pièces de voiture: si quelqu'un veut sa voiture en noir , vous ne devriez pas avoir à repenser la voiture entière pour ce faire. Une voiture et ses pièces détachées seraient un exemple parfait d'une architecture faiblement couplée. Si vous souhaitez remplacer votre moteur par un meilleur, vous devriez pouvoir simplement retirer votre moteur sans trop d'effort et l'échanger contre un meilleur. Si votre voiture ne fonctionne qu'avec des moteurs Rolls Royce 1234 et aucun autre moteur - alors votre voiture sera étroitement couplée à ce moteur (Rolls Royce 1234). Il serait mieux si vous avez changé la conception de votre voiture afin qu'il fonctionne avec toutmoteur, de sorte qu'il est un peu plus lâchement couplé avec ses composants. Ce serait encore mieux si votre voiture pouvait fonctionner sans avoir besoin d'un moteur! Une certaine quantité de couplage va se produire, mais vous devriez travailler pour la minimiser autant que possible. Pourquoi? Parce que lorsque les exigences changent, nous devrions toujours être en mesure de fournir des logiciels de bonne qualité, très rapidement et nous sommes aidés dans ce but par un couplage lâche.
En bref, un couplage lâche facilite le changement de code. Les réponses ci-dessus fournissent un code qui mérite d'être lu à ce stade.
Re: @TimoHuovinen commente - le concept de couplage lâche va de pair avec les concepts de polymorphisme. Si vous comprenez l'analogie de base d'une chemise / pièces de voiture, alors vous serez prêt à donner un sens au polymorphisme. La meilleure façon, à ce stade, est de lire les exemples de code fournis par mes estimables collègues dans les autres réponses sur ce fil. Si je dis plus, vous pourriez être surchargé avec trop d'informations.
Dans la conception orientée objet, la quantité de couplage se réfère à combien la conception d'une classe dépend de la conception d'une autre classe. En d'autres termes, à quelle fréquence les changements dans la classe A sont-ils liés à la force dans la classe B? Un couplage serré signifie que les deux classes changent souvent ensemble, un couplage lâche signifie qu'elles sont pour la plupart indépendantes. En général, un couplage desserré est recommandé car il est plus facile à tester et à entretenir.
Vous pouvez trouver cet article de Martin Fowler (PDF) utile.
En général, le couplage serré est mauvais mais la plupart du temps, car il réduit la flexibilité et la réutilisation du code, il rend les changements beaucoup plus difficiles, il empêche la testabilité, etc.
L'objet étroitement couplé est un objet qui a besoin de se connaître un peu les uns les autres et est généralement très dépendant des autres interfaces. Changer un objet dans une application étroitement couplée nécessite souvent de modifier un certain nombre d'autres objets. Dans une petite application, nous pouvons facilement identifier les changements et il y a moins de chance de manquer quoi que ce soit. Mais dans les grandes applications, ces interdépendances ne sont pas toujours connues de tous les programmeurs ou il y a une chance de manquer des changements. Mais chaque ensemble d'objets faiblement couplés ne dépend pas des autres.
En bref, nous pouvons dire que le couplage lâche est un objectif de conception qui cherche à réduire les interdépendances entre les composants d'un système dans le but de réduire le risque que les changements dans un composant nécessitent des changements dans tout autre composant. Le couplage lâche est un concept beaucoup plus générique destiné à augmenter la flexibilité d'un système, à le rendre plus maintenable et à rendre l'ensemble du cadre plus «stable».
Le couplage fait référence au degré de connaissance directe qu'un élément possède d'un autre. on peut dire un exemple: A et B, seul B change son comportement uniquement quand A change son comportement. Un système à couplage lâche peut être facilement décomposé en éléments définissables.
Lorsque deux objets sont faiblement couplés, ils peuvent interagir mais ont très peu de connaissances l'un de l'autre.
Les conceptions faiblement couplées nous permettent de construire des systèmes OO flexibles capables de gérer le changement.
Le modèle de conception de l'observateur est un bon exemple pour créer des classes librement couplées, vous pouvez y jeter un œil sur Wikipedia .
Un extrait de mon article de blog sur le couplage:
Qu'est-ce que le couplage serré : -
Comme par la définition ci-dessus, un objet étroitement couplé est un objet qui a besoin de connaître d'autres objets et qui est généralement très dépendant des interfaces les uns des autres.
Lorsque nous changeons un objet dans une application étroitement couplée, cela nécessite souvent de modifier un certain nombre d'autres objets. Il n'y a aucun problème dans une petite application, nous pouvons facilement identifier le changement. Mais dans le cas de grandes applications, ces interdépendances ne sont pas toujours connues de tous les consommateurs ou autres développeurs ou il y a de nombreuses chances de changements futurs.
Prenons un code de démonstration du panier pour comprendre le couplage serré:
namespace DNSLooseCoupling
{
public class ShoppingCart
{
public float Price;
public int Quantity;
public float GetRowItemTotal()
{
return Price * Quantity;
}
}
public class ShoppingCartContents
{
public ShoppingCart[] items;
public float GetCartItemsTotal()
{
float cartTotal = 0;
foreach (ShoppingCart item in items)
{
cartTotal += item.GetRowItemTotal();
}
return cartTotal;
}
}
public class Order
{
private ShoppingCartContents cart;
private float salesTax;
public Order(ShoppingCartContents cart, float salesTax)
{
this.cart = cart;
this.salesTax = salesTax;
}
public float OrderTotal()
{
return cart.GetCartItemsTotal() * (2.0f + salesTax);
}
}
}
Problèmes avec l'exemple ci-dessus
Un couplage serré crée des difficultés.
Ici, les OrderTotal()
méthodes nous donnent le montant total pour les articles actuels des chariots. Si nous voulons ajouter les fonctionnalités de réduction dans ce système de chariot. C'est très difficile à faire dans le code ci-dessus car nous devons apporter des modifications à chaque classe car il est très étroitement couplé.
Un couplage lâche signifie que le degré de dépendance entre deux composants est très faible.
Exemple: GSM SIM
Un couplage étroit signifie que le degré de dépendance entre deux composants est très élevé.
Exemple: CDMA Mobile
D'après ce que je comprends, l'architecture à couplage serré n'offre pas beaucoup de flexibilité pour le changement par rapport à l'architecture à couplage lâche.
Mais en cas d'architectures faiblement couplées, de formats de messages ou de plates-formes d'exploitation, ou la refonte de la logique métier n'a pas d'impact sur l'autre extrémité. Si le système est supprimé pour une refonte, bien sûr, l'autre extrémité ne pourra pas accéder au service pendant un certain temps, mais à part cela, la fin inchangée peut reprendre l'échange de messages comme c'était le cas avant la refonte.
Un couplage serré signifie qu'une classe dépend d'une autre classe.
Le couplage lâche signifie qu'une classe dépend de l'interface plutôt que de la classe.
Dans le couplage étroit , il existe des dépendances codées en dur déclarées dans les méthodes.
En accouplement lâche , nous devons passer la dépendance en externe lors de l'exécution au lieu d'être codé en dur. (Les systèmes à couple lâche utilisent l'interface pour réduire la dépendance avec la classe.)
Par exemple, nous avons un système qui peut envoyer une sortie de deux manières ou plus comme la sortie JSON, la sortie CSV, etc.
public interface OutputGenerator {
public void generateOutput();
}
public class CSVOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("CSV Output Generator");
}
}
public class JSONOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("JSON Output Generator");
}
}
// In Other Code, we write Output Generator like...
public class Class1 {
public void generateOutput() {
// Here Output will be in CSV-Format, because of hard-coded code.
// This method tightly coupled with CSVOutputGenerator class, if we want another Output, we must change this method.
// Any method, that calls Class1's generateOutput will return CSVOutput, because Class1 is tight couple with CSVOutputGenerator.
OutputGenerator outputGenerator = new CSVOutputGenerator();
output.generateOutput();
}
}
Dans l'exemple ci-dessus, si nous voulons modifier la sortie en JSON, nous devons rechercher et modifier le code entier, car Class1 est étroitement couplé avec la classe CSVOutputGenerator.
public interface OutputGenerator {
public void generateOutput();
}
public class CSVOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("CSV Output Generator");
}
}
public class JSONOutputGenerator implements OutputGenerator {
public void generateOutput() {
System.out.println("JSON Output Generator");
}
}
// In Other Code, we write Output Generator like...
public class Class1 {
public void generateOutput(OutputGenerator outputGenerator) {
// if you want to write JSON, pass object of JSONOutputGenerator (Dependency will be passed externally to this method)
// if you want to write CSV, pass object of CSVOutputGenerator (Dependency will be passed externally to this method)
// Due to loose couple with class, we don't need to change code of Class1, because Class1 is loose coupled with CSVOutputGenerator or JSONOutputGenerator class
// Any method, that calls Class1's generateOutput will desired output, because Class1 does not tight couple with CSVOutputGenerator or JSONOutputGenerator class
OutputGenerator outputGenerator = outputGenerator;
output.generateOutput();
}
}
Il existe certains outils qui fournissent une injection de dépendance via leur bibliothèque, par exemple dans .net, nous avons la bibliothèque ninject .
Si vous allez plus loin en java, le printemps offre ces capacités.
Des objets à couplage lâche peuvent être créés en introduisant des interfaces dans votre code, c'est ce que font ces sources.
Dites dans votre code que vous écrivez
Myclass m = new Myclass();
maintenant cette déclaration dans votre méthode dit que vous dépendez de myclass
ce qu'on appelle un couplage étroit. Maintenant, vous fournissez une injection de constructeur, ou une injection de propriété et un objet instanciant, puis ils seront couplés de manière lâche.
Il y a beaucoup de bonnes réponses ici en utilisant des analogies, mais un ami au travail m'a donné un exemple que j'aimais plus que toutes celles mentionnées ici ... Les yeux et les lunettes!
Couplage serré
Un couplage étroit serait les yeux. Si je veux réparer ma vision, il est très coûteux d'obtenir une greffe oculaire et comporte beaucoup de risques. Mais que se passe-t-il si le designer (étant la race humaine) trouve une meilleure solution. Ajoutez une fonction qui est lâchement couplée au corps afin qu'elle puisse être facilement modifiée! (oui .. lunettes)
Couplage lâche
Je peux facilement remplacer mes lunettes sans briser ma vision sous-jacente. Je peux enlever les lunettes et ma vision sera comme avant (ni meilleure ni pire). L'utilisation de différentes paires de lunettes change la façon dont nous voyons le monde à travers nos yeux avec peu de risques et une facilité d'entretien facile.
Résumé
La prochaine fois, quelqu'un vous demandera "qui se soucie si mon code est étroitement couplé?" La réponse réside dans l'effort de changement, l'effort de maintien et le risque de changement.
Alors, comment cela se fait-il en C #? Interfaces et injection de dépendances!
ÉDITER
C'est aussi un bon exemple du modèle Decorator, où les yeux sont la classe que nous décorons en répondant aux exigences de l'interface mais en donnant des fonctionnalités différentes (par exemple, lunettes de soleil, lunettes de lecture, loupes pour les bijoutiers, etc.)
Le couplage lâche est et répond aux anciennes dépendances codées en dur et aux problèmes liés aux problèmes comme la recompilation fréquente lorsque quelque chose change et la réutilisation du code. Il met l'accent sur l'implémentation de la logique de travail dans les composants et sur l'évitement du code de câblage spécifique à la solution.
Couplage lâche = IoC Voir ceci pour une explication plus facile.
Le couplage lâche est le processus consistant à donner indirectement la dépendance dont votre classe a besoin sans fournir toutes les informations de la dépendance (c'est-à-dire dans l'interface de provenance) au cas où le couplage serré que vous donnez directement dans la dépendance n'est pas un bon moyen de codage.
Il s'agit du taux de dépendance des classes par rapport à d'autres, qui est si faible en couplage lâche et si élevé en couplage serré. Pour être clair dans l' architecture d'orientation des services, les services sont faiblement couplés les uns aux autres par rapport aux classes monolithiques dont la dépendance les unes aux autres est exprès
Si la création / existence d'un objet dépend d'un autre objet qui ne peut pas être adapté, son couplage étroit. Et, si la dépendance peut être adaptée, son couplage lâche. Prenons un exemple en Java:
class Car {
private Engine engine = new Engine( "X_COMPANY" ); // this car is being created with "X_COMPANY" engine
// Other parts
public Car() {
// implemenation
}
}
Le client de Car
classe peut en créer un avec UNIQUEMENT le moteur "X_COMPANY".
Pensez à rompre ce couplage avec la possibilité de changer cela:
class Car {
private Engine engine;
// Other members
public Car( Engine engine ) { // this car can be created with any Engine type
this.engine = engine;
}
}
Maintenant, a Car
ne dépend pas d'un moteur de "X_COMPANY" car il peut être créé avec des types.
Une remarque spécifique à Java: utiliser des interfaces Java uniquement pour le découplage n'est pas une approche appropriée. En Java, une interface a un but - agir comme un contrat qui fournit intrinsèquement un comportement / avantage de découplage.
Le commentaire de Bill Rosmus dans la réponse acceptée a une bonne explication.
Un couplage étroit signifie que les classes et les objets dépendent les uns des autres. En général, le couplage serré n'est généralement pas bon car il réduit la flexibilité et la réutilisation du code tandis que le couplage lâche signifie la réduction des dépendances d'une classe qui utilise directement les différentes classes.
Couplage étroit L'objet étroitement couplé est un objet qui a besoin de connaître d'autres objets et qui dépend généralement fortement des interfaces des uns et des autres. La modification d'un objet dans une application étroitement couplée nécessite souvent de modifier un certain nombre d'autres objets. Dans les petites applications, nous pouvons facilement identifier les changements et il y a moins de chance de manquer quoi que ce soit. Mais dans les grandes applications, ces interdépendances ne sont pas toujours connues de tous les programmeurs et il y a une chance d'ignorer les changements. Exemple:
class A {
public int a = 0;
public int getA() {
System.out.println("getA() method");
return a;
}
public void setA(int aa) {
if(!(aa > 10))
a = aa;
}
}
public class B {
public static void main(String[] args) {
A aObject = new A();
aObject.a = 100; // Not suppose to happen as defined by class A, this causes tight coupling.
System.out.println("aObject.a value is: " + aObject.a);
}
}
In the above example, the code that is defined by this kind of implementation uses tight coupling and is very bad since class B knows about the detail of class A, if class A changes the variable 'a' to private then class B breaks, also class A's implementation states that variable 'a' should not be more than 10 but as we can see there is no way to enforce such a rule as we can go directly to the variable and change its state to whatever value we decide.
Output
aObject.a value is: 100
Loose Coupling
Loose coupling is a design goal to reduce the inter-dependencies between components of a system with the goal of reducing the risk that changes in one component will require changes in any other component.
Loose coupling is a much more generic concept intended to increase the flexibility of the system, make it more maintainable and makes the entire framework more stable.
Example:
class A {
private int a = 0;
public int getA() {
System.out.println("getA() method");
return a;
}
public void setA(int aa) {
if(!(aa > 10))
a = aa;
}
}
public class B {
public static void main(String[] args) {
A aObject = new A();
aObject.setA(100); // No way to set 'a' to such value as this method call will
// fail due to its enforced rule.
System.out.println("aObject value is: " + aObject.getA());
}
}
Dans l'exemple ci-dessus, le code défini par ce type d'implémentation utilise un couplage lâche et est recommandé car la classe B doit passer par la classe A pour obtenir son état où les règles sont appliquées. Si la classe A est modifiée en interne, la classe B ne se cassera pas car elle utilise uniquement la classe A comme moyen de communication.
Output
getA() method
aObject value is: 0