J'ai un examen des modèles de logiciels cette semaine et l'un des sujets que nous devons étudier est le couplage efférent et afférent.
Je comprends qu'un emballage a un Ce élevé (couplage efférent) s'il dépend d'un certain nombre d'autres types.
Par exemple:
class Car{
Engine engine;
Wheel wheel;
Body body;
}
Cette classe aurait un couplage efférent élevé car elle dépend des types de moteur, de roue et de carrosserie.
Alors que le type "Wheel" aurait un Ca élevé (couplage afférent) si plusieurs autres colis en dépendaient (Voiture, Avion, Vélo).
L'une des questions possibles de notre examen est la suivante: quand le couplage Efférent / Afférent est-il bon ou mauvais? Cela me semble étrange car logiquement un programme aurait besoin de packages / classes avec un couplage Efferent / Afferent élevé.
Quelqu'un at-il un exemple de quand / où un couplage efférent ou afférent élevé est bon / mauvais ??
Merci !
la source
Réponses:
Le couplage afférent peut être évalué plus facilement en fonction de la quantité de douleur qu'il provoque / enregistre en raison de la nécessité ou de la probabilité d'un changement. Par exemple, prenez votre classe de roue et disons que beaucoup d'autres modules l'utilisent pour construire différents types de véhicules. Si la classe de roue est extrêmement stable, cet accouplement afférent est avantageux car les véhicules ont besoin de roues et ils en utilisent une fiable. Si, d'autre part, la classe de roue est volatile en termes de maintenance, ce couplage afférent va être un point douloureux lorsque vous introduisez des changements de rupture à plusieurs reprises dans beaucoup de code.
Le couplage efférent est similaire dans le concept, mais vous allez regarder une proposition de valeur légèrement différente. Si vous avez une classe de voiture qui dépend directement de beaucoup de pièces individuelles (par opposition à dire "Moteur" et "Châssis" seulement, et elles se composent d'autres sous-parties), la classe fait probablement beaucoup et peut donc être un goulot d'étranglement de maintenance. Les modifications de cette classe sont susceptibles d'être difficiles et risquées en raison de sa complexité. D'un autre côté, si le couplage efférent est élevé, mais qu'il est en fait assez cohérent et clair, vous n'avez pas à vous soucier d'une hiérarchie d'objets et de relations.
En ce qui concerne l'architecture / la conception, ce que vous devez vraiment considérer, ce sont à peu près des compromis sans fin et ces mesures ne sont pas différentes. Si vous voulez trouver un exemple de quelque chose de bon ou de mauvais, jouez au jeu de simulation. Imaginez un exemple et dites "et si je voulais faire X - combien cela serait nul?" Pour X où la réponse est «beaucoup», vous avez un inconvénient et pour X où la réponse est «ce serait vraiment très facile», vous avez un avantage.
la source
Parlant en généralités, couplage lâche:
positif : protège une partie du système des changements dans quelque chose dont il dépend (couplage afférent)
négatif : la relation peut être plus difficile à comprendre
Par exemple, si je développais un système qui reposait sur HTTTP, je déciderais si je dois coupler étroitement ou sans serrer à HTTP. Si je pensais que le système était susceptible de passer à un protocole différent, je pourrais choisir de le coupler librement, tandis que si j'acceptais que HTTP était mon protocole, je pourrais le coupler étroitement à ce protocole pour plus de simplicité dans la compréhension.
Considérez que certaines des complexités de WS * résident dans son découplage de HTTP en tant que protocole.
la source
Afférent
Si quelque chose utilise un tas de choses différentes (nombre élevé de couplages afférents), il pourrait être susceptible de se casser si l'une de ces choses change.
Instabilité = 1
Efférent
Si quelque chose est utilisé par un tas de choses différentes (nombre élevé de couplages efférents), il pourrait être enclin à casser beaucoup de choses s'il change.
Instabilité = 0
Stabilité
La définition de Martin de la «stabilité» est un mélange exotique entre «difficile à changer» et «ayant peu de raisons de changer». Pourtant, sa métrique d'instabilité ne décrit que "la difficulté du changement". Les «raisons de changer» auront beaucoup plus à voir avec des facteurs qui ne peuvent pas être facilement calculés, comme la conception appropriée de vos interfaces, à un niveau d'abstraction approprié, et la compréhension plus claire des exigences de l'utilisateur.
Donc, un couplage efférent élevé avec un couplage afférent faible donne de la stabilité (comme dans quelque chose de difficile à changer car il cassera un tas de trucs), l'inverse génère une instabilité (comme dans quelque chose de facile à changer car il ne cassera pas un tas de choses) .
Un grand nombre de couplages afférents pourrait être un indicateur que votre conception manque de concentration - elle utilise tout un tas de choses différentes, donc il lui manque peut-être une responsabilité claire et singulière.
Un grand nombre de couplages efférents pourraient initialement être interprétés comme une très bonne chose, car cela indique que votre conception est largement (ré) utilisée. Pourtant, ce serait mauvais si vous êtes tenté de changer souvent le design de manière à tout casser. Ainsi, avec un grand nombre de couplages efférents, il est nécessaire que ces boîtiers aient "peu ou pas de raisons de changer". Les dessins doivent être stables dans le sens idéal de ne pas avoir de raisons de changer, car ils seront également très difficiles à changer.
Principe d'abstractions stables
Des concepts comme l'inversion de dépendance (qui appelle naturellement l'injection de dépendance) et SAP (principe d'abstractions stables) suggèrent tous que les dépendances se dirigent vers les abstractions. Et il y a une raison simple pour considérer la "stabilité" dans le contexte d'avoir "peu de raisons de changer". Une interface abstraite ne mentionne aucun détail concret, elle se concentre uniquement sur "ce qu'il faut faire" au lieu de "ce que sont les choses", et a donc moins de raisons de changer. Le port graphique accéléré de nos cartes mères (interface abstraite) a moins de raisons de subir une modification de conception que le GPU qui s'y branche (un détail concret).
Réutilisation vs réutilisation
Une sorte de métrique personnelle, si je peux en suggérer une qui entre quelque peu en collision avec celle de Martin, est cette notion que j'aime pousser à ce que les bibliothèques les plus réutilisables devraient chercher à réutiliser au minimum d'autres codes. Cela pousse l'instabilité vers un 0 difficile. C'est pour des raisons pratiques d'avoir des raisons minimales de changer, mais aussi pour promouvoir la bibliothèque la plus facile à déployer. Une bibliothèque polyvalente et largement utilisée qui dépend d'une douzaine de bibliothèques différentes a de nombreuses raisons de changer, ainsi qu'une distribution groupée maladroitement qui peut être difficile à déployer. La différence ici est que les "raisons de changer" dans mon cas s'étendent même à l'implémentation, car elles proviennent d'une vue orientée bibliothèque qui cherche à publier des versions stables de la bibliothèque. Martin pourrait ignorer la mise en œuvre en tant que partie très distincte,
Du point de vue de la distribution, l'implémentation et l'interface se confondent pour produire des dépendances utilisateur à une bibliothèque stable ou instable. Du point de vue de l'interface, seule l'interface est utilisée et les détails d'implémentation associés sont complètement séparés.
la source