2008-12-12 8 views
12

Je suis juste en train de lire le code complet par Steve McConell et je pense à un exemple qu'il donne dans une section sur le couplage lâche. Il s'agit de l'interface d'une méthode qui calcule le nombre de jours fériés pour un employé, qui est calculé à partir de la date d'entrée de l'employé et de ses ventes. L'auteur suggère d'avoir la date d'entrée et les ventes que les paramètres de la méthode au lieu d'une instance de l'employé:Couplage lâche contre cachette de l'information et facilité de changement

int holidays(Date entryDate, Number sales) 

au lieu de

int holidays(Employee emp) 

L'argument est que ce découple le client du méthode car elle n'a pas besoin de savoir quoi que ce soit sur la classe Employee.

Deux choses sont venues à l'esprit:

  1. Fournir tous les paramètres nécessaires pour l'encapsulation des pauses de calcul. Il montre les internes de la méthode sur la façon dont il calcule le résultat.

  2. Il est plus difficile de changer, par ex. lorsque quelqu'un décide que l'âge de l'employé doit également être inclus dans le calcul. Il faudrait changer la signature.

Quelle est votre opinion?

+0

Essayer de chercher ceci sur le livre. Pouvez-vous citer le chapitre/la section? – jop

+0

C'est le chapitre 5.3, page 105. Mais c'est l'édition allemande. – cretzel

Répondre

9

Les problèmes que je vois avec votre argument numéro 2 sont

  1. vous assumez toutes les valeurs nécessaires provient d'une instance de l'employé. Ce n'est en aucun cas toujours vrai. Par exemple, disons que vous devez tenir compte de l'état financier de l'entreprise pour calculer combien de "vacances bonus" donner à un employé. Souhaitez-vous ajouter des informations sur l'état financier à la classe des employés pour éviter de modifier la signature? Changer une signature n'est pas nécessairement «plus difficile», surtout en ces jours d'outils qui mettront en évidence chaque lieu d'appel au clic d'un bouton.

Et le principal problème avec votre argument numéro 1 est qu'il ne rompt tout simplement pas l'encapsulation comme tout le monde l'a dit. Vous montrez le quoi, pas le comment, ce qu'est l'encapsulation.

1

1) Fournir des paramètres ne rompt pas l'encapsulation. Cela montre simplement que ces paramètres sont utilisés pour calculer les vacances. Le "COMMENT" est toujours caché à l'intérieur de la méthode.

2) La méthode Holiday ne doit pas faire partie de la classe Employee.

+0

Pour le # 2, je ne pense pas qu'il suggère que la méthode des vacances fait partie de la classe des employés. – BobbyShaftoe

+0

Désolé de supposer que. Je n'ai pas encore lu un bon livre comme "code complet" – shahkalpesh

+0

Cela fait longtemps que je ne l'ai pas lu, je pense que je peux le reprendre. – BobbyShaftoe

1
  1. Ceci ne brise pas l'encapsulation. Briser l'encapsulation révélerait les méthodes internes utilisées pour calculer les vacances. Fournir les paramètres de départ est ce qui définit l'API. L'API pourrait être améliorée pour permettre de tels changements - cependant, la plupart des approches suggèrent que vous devriez concevoir pour répondre aux exigences actuelles et ne pas surpasser pour des changements imprévus (concevoir pour le changement, mais ne pas essayer de prédire le changement). Il vaut mieux implémenter ce dont vous avez besoin maintenant et refactoriser plus tard si nécessaire.

À mon avis, il est préférable de prévoir le changement par le découplage et l'encapsulation autant que possible afin que refactoring pourrait se faire aussi facilement que possible. Tenter de prédire à l'avance chaque scénario possible se termine avec un système sur-conçu gonflé.

+0

# 2 est ce que j'entends de beaucoup de propagandistes agiles et je m'inquiète que ce soit juste à trop courte vue. – BobbyShaftoe

+0

Ce n'est pas à courte vue, c'est juste pragmatique. Après avoir appris par vous-même ce dont vous avez besoin en le codant, vous pouvez commencer à améliorer la conception si nécessaire. –

+0

Mais cela vous semble-t-il toujours pragmatique lorsque vous êtes dans une situation où vous devez modifier l'API? Je veux dire, beaucoup d'arguments dans le monde agile prétendent le pragmatisme mais je me demande si c'est vraiment le cas. – BobbyShaftoe

0

Je dirais que l'un des principaux avantages du couplage lâche est la facilité de changement. Les types faiblement couplés peuvent changer indépendamment les uns des autres donc je ne comprends pas votre "vs" dans la question.

En outre, je ne dirais pas que vous rompez l'encapsulation en fournissant des paramètres pour la méthode. Vous pouvez implémenter un Sum(int a, int b) comme vous voulez - mais vous devez me dire (en tant qu'utilisateur) que vous attendez deux nombres.

1
int holidays(Employee emp) 

Dans ce cas, seul un employé peut utiliser la fonction en question ...

+1

Eh bien, mais son point est que si vous avez besoin de changer quelles sont les valeurs nécessaires pour calculer les vacances, alors la signature aurait besoin d'être changé. Cependant, si un autre type d'objet pouvait avoir des "vacances" calculées, vous pourriez peut-être ajouter une méthode surchargée. Je pense que c'est une question intéressante. – BobbyShaftoe

0

Contrairement à d'autres articles, je suis d'accord avec vous que cela casse l'encapsulation. Pas l'encapsulation d'une classe, mais le concept de calcul des vacances. Si vous voulez changer la façon dont ce calcul fonctionne à l'avenir, et encore éviter le couplage serré, je suggérerais de faire de Employee une interface. Si cela est encore trop étroitement lié à Employee parce que vous pensez que les vacances pourraient devoir être calculées pour d'autres choses, alors vous pourriez avoir une interface GetsHolidays dont héritera Employee.

Bien entendu, l'implication de la solution choisie dépend de la gravité des problèmes de couplage et d'encapsulation. Je considère que les deux solutions originales sont acceptables dans de nombreuses situations, gardez-les simples si possible.

6

Lâche finalement coupling gagne. Du haut couplage faible, il existe différentes classes de couplage:

  1. couplage contenu (élevé): On modifie module ou repose sur le fonctionnement interne d'un autre module
  2. couplage commun: deux modules partagent la mêmes données globales (par exemple une variable globale ). La modification de la ressource partagée implique la modification de tous les modules qui l'utilisent.
  3. Couplage externe: deux modules partagent un format de données imposées de l'extérieur, un protocole de communication ou une interface de périphérique .
  4. Couplage de contrôle: un module contrôlant la logique d'un autre, par en lui transmettant des informations sur ce qu'il faut faire (par exemple en passant un drapeau "quoi faire").
  5. couplage de timbres (couplage de données structuré): lorsque les modules partagent une structure de données composite et utiliser seulement une partie de celui-ci, éventuellement un partie différente (par exemple, le passage d'un ensemble enregistrement à une fonction qui n'a besoin que un champ de il).
  6. Couplage de données: lorsque des modules partagent des données via, par exemple, des paramètres. Chaque donnée est une pièce élémentaire, et sont les seules données qui sont partagées (par exemple, en passant un entier à une fonction qui calcule une racine carrée ).
  7. couplage de message (bas): Les modules ne sont pas dépendants les uns des autres , ils utilisent plutôt une interface public pour échanger des paramètres moins- messages (ou des événements, voir Message passing).
  8. Aucun couplage: les modules ne communiquent pas du tout entre eux.

Passe en Employee est Stamp couplage, qui est couplé de plus de couplage de données. Si vous pensez vraiment à la facilité de modification, un faible couplage est préférable car vous avez moins à vous soucier des effets secondaires indésirables. Supposons que vous souhaitiez modifier la structure de la classe Employee. Vous devez maintenant vérifier l'implémentation réelle de la fonction vacances pour vous assurer qu'elle ne rompt pas les calculs.

Le meilleur moyen le plus découplé est de définir une interface IHolidayable, mais c'est une surcharge pour cette situation.

0

La meilleure façon la plus découplé est de définir une interface IHolidayable

Ce genre de déclaration générale me fâche vraiment. Ce n'est pas parce que vous utilisez une interface que vous déconnectez automatiquement quoi que ce soit. Si votre classe d'employés implémente une interface pour calculer les jours fériés, tout code appelant la méthode, appelle toujours la même méthode. Au pire, le code d'appel le fera par un accès direct à un objet employé, et non une référence d'interface IHolidayable, auquel cas vous avez seulement aggravé la situation (car il y a maintenant un couplage plus subtil entre l'interface et les classes Mettre en œuvre). Les interfaces peuvent en effet aider au découplage, mais elles ne le font pas automatiquement, et même lorsqu'elles le font, elles ne sont pas nécessairement une meilleure solution qu'une classe abstraite (ou une autre ancêtre).

+0

J'espère que vous ne pensez pas que je voulais dire que l'interface est une solution miracle pour chaque situation. Aussi, vous avez omis ma seconde moitié de la phrase "mais c'est une surcharge pour cette situation." Le passage d'une interface définie au minimum à la place de l'objet natif est une forme de couplage de message. –

2

Pour moi, la "bonne" réponse se résume à savoir si vous définissez une API de haut niveau ou de bas niveau lors de la création de cette fonction. Une API de bas niveau met la flexibilité au-dessus de la commodité pour un cas particulier et plaide pour int holidays(Date entryDate, Number sales) . Une API de haut niveau est conçue pour bien faire une chose avec autant de commodité que possible pour le client. Ceci plaide pour int holidays(Employee emp) car il nécessite moins d'informations de la part de l'appelant (extraction de la date et des ventes de la classe Employé) et est moins verbeux.

0
int holidays (IHolidayInfo obj) 

Cela pourrait être un moyen. Dans ce cas, tout objet qui implémente IHolidayInfo pourrait utiliser la fonction "vacances". Juste une alternative.

Questions connexes