J'ai un objet composite (je l'appellerai A
) qui a un nombre fixe de fils (je les appellerai A1
Et A2
)
Tous ont une méthode Accept(Visitor)
.
J'ai une interface graphique A
est la fenêtre principale qui consiste en de nombreuses sous-fenêtres (A.K.A A1
Et A2
). Les visiteurs seront des visiteurs lorsqu'un utilisateur clique sur un bouton pour lancer une nouvelle opération, telle que Déménagement d'un nouveau jeu, devine un mot incorrectement et d'autres événements. (Command
Motif de conception est utilisé, mais ceci est hors de portée) et lorsque de tels événements marquent, le visiteur mettra à jour l'interface graphique de manière appropriée.
Lorsque vous envisagez comment implémenter Accept(Visitor)
à A
, je considère la météo que je devrais cascader la requête Accept(Visitor)
demande à A1
Et A2
bien ou pas.
Voici mon argument pour cascade:
Plus de transparence - dans tous mes visiteurs jusqu'à présent, je veux passer sur les fils de A
. Mais pour faire cela sans cascade, j'aurai besoin de getters pour les fils de A
, mais les fils de A
peuvent changer (même au moment de l'exécution, si je modifie la mise en œuvre d'une quantité fixe de fils à une collection) et je ne souhaite pas modifier l'interface tout le temps nécessaire pour prendre en charge de telles opérations. Vous pouvez suggérer des itérateurs pour cela, mais c'est que le visiteur voudra peut-être visiter A1
Et A2
, Mais si un autre A3
Son sera ajouté, il pourrait ne pas vouloir pour le visiter. Donc, comme il itère à travers A
sons, il doit recourir à la vérification de type laid, ce qui est ce que le modèle de conception des visiteurs est venu éradiquer. Au lieu de cela, il pourrait être beaucoup plus facile de simplement cascader toutes les demandes aux enfants et si un visiteur n'est pas intéressé à visiter un type de type, il ne peut pas simplement quitter la méthode de la visite à vide. De plus, au niveau symbolique, A1
Et A2
sont une partie de A
, donc la cascade a du sens.
Voici mon argument contre cascade:
Couplage de lâche - Cascade signifie que vous forcez le visiteur à visiter des enfants, cela pourrait ne pas vouloir visiter, ce qui peut conduire à des résultats inattendus. De plus, cela pourrait ne pas soutenir accepter les types des enfants. Si des getter ou des itérateurs sont utilisés, le visiteur peut choisir la météo qu'il souhaite passer sur les enfants.
Quelle approche dois-je prendre?
Il n'y a pas de meilleure réponse à votre question. Ce n'est pas sans raison que gof a laissé cette question ouverte:
(p.339) qui est responsable de la traversée de la structure d'objet? (...) Nous pouvons assumer la responsabilité de Traversal dans l'un des trois endroits: dans la structure de l'objet, dans le visiteur ou dans un objet itérateur séparé.
Souvent, la structure d'objet est responsable de l'itération. (...) Un composite se déplacera couramment en ayant chacun une opération
Accept
traverse les enfants de l'élément et appelezAccept
sur chacune d'elles de manière récursive.
C'est ce que vous appelez en cascade. Il est souvent utilisé de cette façon, car la structure d'objet connaît le mieux sa structure et comment la traverser. Si vous avez donné cette responsabilité au visiteur, vous devrez peut-être reproduire la logique de traversée dans tous les visiteurs concrets (à moins que vous ne parveniez à mettre en œuvre Accept
à l'aide du modèle de méthode de modèle).
Mettre l'entraînement dans le visiteur est d'intérêt principalement pour des algorithmes de visite complexes, lorsque la traversée dépend des résultats intermédiaires de la visite (GOF donne un exemple de cette situation). Mais cette approche n'est pas un couplage plus lâche: il s'agit d'un couplage plus fort car le visiteur doit en savoir plus sur la traversée.
Si le couplage de lâche est votre principale préoccupation, vous pouvez utiliser l'approche que vous n'avez pas mentionnée: déplacez la logique de traversée dans un itérateur. Construisez le visiteur d'une manière qu'il utilise cet itérateur spécial et laissez le visiteur décider de quels nœuds qui s'intéressent. Mais dans la plupart des cas, cela conduira à un code très complexe par rapport à une cascade beaucoup plus simple et robuste.