Je sais quel modèle de visiteur est et comment l'utiliser; Cette question n'est pas un duplicata de ce un . p>
J'ai une bibliothèque où je mets la majeure partie du code réutilisable que j'écris et que je lie à la plupart de mes projets. P>
Souvent, je dois ajouter des fonctionnalités à certaines classes, mais sans ajouter ces nouvelles fonctionnalités à la bibliothèque. Laissez-moi utiliser un exemple réel: p>
dans cette lib, j'ai une classe Je développe maintenant une application graphique où j'ai besoin de rendre ces code> code>, mais je ne veux pas mettre une fonction virtuelle Le moyen le plus célèbre de le faire consiste à utiliser le modèle de visiteur, bien sûr, mais cela apparaît quelques-uns quelques doutes dans mon esprit: P>
Toute classe de toute bibliothèque peut être étendue comme mon Modèle de visiteur est un moyen de simuler une double dispatching en C ++. Il n'est pas indigène en C ++ et nécessite d'être explicitement mis en œuvre, ce qui rend l'interface de classe plus complexe: je ne pense pas que la fonction explicitement up-casting Alors, que dois-je faire? Mise en œuvre double envoi dans toutes mes classes de bibliothèque? Et si la bibliothèque fournissant forme code>, héritée par
cercleshape code>,
polygonshape code> et
composithape code>. p>
rendu code> dans le noyau
dans le noyau
Forme code> classe, puisque certains de mes projets utilisant
forme code> ne font pas de rendu, et d'autres projets graphiques pourraient utiliser différents moteurs de rendu (j'utilise QT pour ce projet, mais pour Un jeu J'utiliserais OpenGL, ainsi que la fonction
rendu code> nécessitera des implémentations différentes). P>
forme code>. La plupart des bibliothèques publiques (à propos de tous) ne fournissent aucun soutien au motif des visiteurs; Pourquoi? Pourquoi devrais-je? p>
ApplyVisitor code> doit être au même niveau de fonctions de mes catégories, je vois ceci comme briser l'abstraction. P>
forme code> avec
dynamic_cast code> est plus cher, mais cela ressemble à une solution plus propre. P>
forme code> n'était pas la mienne, mais une bibliothèque GPL trouvée sur Internet? P>
5 Réponses :
Cela ne ressemble pas à un cas pour le motif de visiteur pour moi. P>
Je vous suggérerais d'avoir un Si vous souhaitez prendre en charge plusieurs moteurs de rendu, vous pouvez avoir une classe de base CODE> RENDERCONTEXT CODE> Abstract Dessin Opérations, avec des sous-classes pour chaque moteur de rendu, chaque sous-classe mettant en œuvre les opérations de dessin en termes de son moteur de rendu. . Vous avez alors renderableadape Code> Classe qui s'agit d'objet code> de forme code>, puis créez des sous-classes pour chaque forme.
Renderableadape (code> aurait un
virtuel code> méthode. P>
Renderableadape :: Render Code> Prenez un
RenderContext Code> comme argument et tirez-le à l'aide de son API abstraite. P>
Certaines fonctions au sein de ma bibliothèque retourner les pointeurs / références à Forme CODE>. Par exemple, le
composithape Code> J'ai parlé d'avoir un ensemble de
forme * code> qui peut être de quelque sorte. Donc, même si je continue dans une classe wrapper (
renderableadape code>), la forme code> allouée dans le code de l'application, je ne serais pas en mesure de gérer la forme
* < / code> retourné par les fonctions de la bibliothèque.
Vous ne pouvez pas simplement envelopper la forme code> renvoyée code>?
Oui, mais en l'enveloppant dans quoi? Je ne sais pas si c'est un cerclehape ou une polygone ... aurait besoin d'une sorte de moulage, mais alors pourquoi déranger avec l'emballage? Je pourrais toujours l'utiliser.
Il y a donc une classe XXXPape, qui contient d'une manière ou d'une autre, des informations "conduisent" le rendu. Pour les cercles qui pourraient être centraux, un rayon, des carrés de certaines coordonnées de coin ou d'autres. Peut-être d'autres choses sur les plombages et les couleurs.
Vous ne voulez pas mettre à jour ces classes pour ajouter la logique de rendu réelle, et je pense que vos raisons de ne pas le faire sont valables / inévitables. p>
mais probablement, vous avez suffisamment de méthodes d'accès public sur les classes pour vous permettre d'obtenir des informations "Conduite", sinon vous êtes condamné. P>
Donc, alors auquel cas pourquoi pouvez-vous non seulement enveloppez ces éléments: p> et ainsi de suite. Utilisez maintenant le motif de visiteur dans les classes de rendu. P> p>
Certaines fonctions au sein de ma bibliothèque retourner les pointeurs / références à Forme CODE>. Par exemple, le
composithape Code> J'ai parlé d'avoir un ensemble de
forme * code> qui peut être de quelque sorte. Donc, même si je garde dans une classe wrapper, la forme code> allouée dans le code de l'application, je ne pourrais pas gérer la forme
la forme * code> renvoyée par les fonctions de la bibliothèque.
Il y a beaucoup de solutions possibles, mais vous pouvez le faire, par exemple: Démarrer une nouvelle hiérarchie, qui rend les formes code> dans un contexte code> spécifique code>:
Certaines fonctions au sein de ma bibliothèque retourner les pointeurs / références à Forme CODE>. Par exemple, le
composithape Code> J'ai parlé d'avoir un ensemble de
forme * code> qui peut être de quelque sorte. Donc, même si je garde dans une classe wrapper, la forme code> allouée dans le code de l'application, je ne pourrais pas gérer la forme
la forme * code> renvoyée par les fonctions de la bibliothèque.
Premier: "" Visiteur est un moyen de simuler une double dispatching en C ++. " EM> Ceci est, erm, pas complètement juste. En fait, Double Dispatch est une forme d'une multiplication multiple, ce qui est un moyen de simuler (les manquages) multi-méthodes en C ++. p>
Si les opérations sur une hiérarchie de classe doivent être mises en œuvre par Ajout de fonctions virtuelles em> strong> ou par ajout de visiteurs em> strong> est déterminé par les probabilités d'ajouter des classes par rapport à l'ajout d'opérations: p>
Oui, de nombreuses bibliothèques ne sont pas livrées avec une interface visiteur. Toutefois, avec des bibliothèques tiers, il y a un autre aspect à cela: généralement, les utilisateurs ne peuvent généralement pas changer les classes de la bibliothèque. C'est-à-dire que si elles ont besoin d'ajouter une opération,
Lorsque nous examinons simplement le raisonnement ci-dessus, cela serait correct si le nombre de classes change souvent. C'est-à-dire que si une bibliothèque est relâchée souvent, les nouvelles classes étant ajoutées constamment, la fourniture d'une interface visiteur n'aurait pas fort de sens, car chaque fois qu'une nouvelle version apporte de nouvelles classes, tout le monde utilisant la bibliothèque doit adapter tous leurs visiteurs . Donc, si nous avons examiné uniquement le raisonnement ci-dessus, une interface visiteur ne semblerait servir que de ne être utile que si le nombre de classes dans une hiérarchie de classe LIB est rarement ou jamais change. p>
Donc, si vous écrivez une bibliothèque et que vous sentez que les utilisateurs devraient pouvoir y ajouter des opérations, vous devez fournir à eux de branler leurs visiteurs dans votre liber em> strong> . p>
Vous pensez donc que je devrais ajouter un soutien aux visiteurs dans ma bibliothèque? Pourriez-vous me dire de toute bibliothèque qui utilise le modèle de visiteur pour me permettre de prendre l'inspiration? Le seul que je connaisse est Boost :: Variante, mais ce cas est très différent d'une utilisation "normale" comme la mine.
@peoro: Je ne saurais pas, car je ne connais pas votre lib. Franchement, je ne peux pas penser à un seul C ++ Lib qui vient avec les visiteurs. Je suis d'accord que boost :: variante code> n'est-il pas votre visiteur quotidien de l'usine. Je suis désolé d'être si peu d'aide.
Je comprends absolument ce que vous avez dit et que je partage les mêmes préoccupations. Le problème est que le modèle de visiteur n'est pas très clairement défini et la solution d'origine pour elle est trompeuse, IMHO. C'est pourquoi il y a tellement de variations de ce modèle. P>
En particulier, je pense que la mise en œuvre correcte devrait prendre en charge le code hérité, je veux dire: un binaire Vous avez perdu le code source du tout, n'est-ce pas? C'est ce que la définition dit: que vous ne devriez jamais avoir à modifier les structures de données d'origine. P>
Je n'aime pas les implémentations avec Visita, Visitb, Visuwayver, accepta, accepter, accepter. C'est absolument faux, imho. P>
Si vous avez une chance, veuillez consulter Un article que j'ai écrit à propos de ce . P>
C'est Java, mais vous pouvez passer à C ++ facilement si vous le trouvez utile à vos besoins. P>
J'espère que cela aide p>
acclamations p>
Le motif de visiteur n'est pas un moyen d'obtenir plusieurs envois. Il a besoin de plusieurs envois et une technique pour imiter plusieurs envoi est généralement enseignée aux programmeurs C ++ dans le cadre du motif visiteur.
Avez-vous besoin de plusieurs envisages? Peut-être que le modèle NVI suit vos besoins. Il semble que une conception NVI puisse aider, mais elle nécessite une méthode de type virtuel virtuel non virtuelle et privée. Donc peut-être une classe abstraite entre la forme et la formeCircle appelée ShaperendinEngine. Sypecircle pourrait ensuite dériver de la forme ou de Shaperenderengine .....