9
votes

C ++: Doutes sur le motif de visiteur

Je sais quel modèle de visiteur est et comment l'utiliser; Cette question n'est pas un duplicata de ce un .


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.

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:

dans cette lib, j'ai une classe forme , héritée par cercleshape , polygonshape et composithape .

Je développe maintenant une application graphique où j'ai besoin de rendre ces , mais je ne veux pas mettre une fonction virtuelle rendu dans le noyau dans le noyau Forme classe, puisque certains de mes projets utilisant forme 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 nécessitera des implémentations différentes).

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:

Toute classe de toute bibliothèque peut être étendue comme mon forme . La plupart des bibliothèques publiques (à propos de tous) ne fournissent aucun soutien au motif des visiteurs; Pourquoi? Pourquoi devrais-je?

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 ApplyVisitor doit être au même niveau de fonctions de mes catégories, je vois ceci comme briser l'abstraction.

explicitement up-casting forme avec dynamic_cast est plus cher, mais cela ressemble à une solution plus propre.


Alors, que dois-je faire? Mise en œuvre double envoi dans toutes mes classes de bibliothèque? Et si la bibliothèque fournissant forme n'était pas la mienne, mais une bibliothèque GPL trouvée sur Internet?


2 commentaires

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 .....


5 Réponses :


0
votes

Cela ne ressemble pas à un cas pour le motif de visiteur pour moi.

Je vous suggérerais d'avoir un renderableadape Classe qui s'agit d'objet de forme , puis créez des sous-classes pour chaque forme. Renderableadape aurait un virtuel méthode.

Si vous souhaitez prendre en charge plusieurs moteurs de rendu, vous pouvez avoir une classe de base RENDERCONTEXT 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 :: Render Prenez un RenderContext comme argument et tirez-le à l'aide de son API abstraite.


3 commentaires

Certaines fonctions au sein de ma bibliothèque retourner les pointeurs / références à Forme . Par exemple, le composithape J'ai parlé d'avoir un ensemble de forme * qui peut être de quelque sorte. Donc, même si je continue dans une classe wrapper ( renderableadape ), la forme 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 renvoyée ?


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.



0
votes

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.

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é.

Donc, alors auquel cas pourquoi pouvez-vous non seulement enveloppez ces éléments: xxx

et ainsi de suite. Utilisez maintenant le motif de visiteur dans les classes de rendu.


1 commentaires

Certaines fonctions au sein de ma bibliothèque retourner les pointeurs / références à Forme . Par exemple, le composithape J'ai parlé d'avoir un ensemble de forme * qui peut être de quelque sorte. Donc, même si je garde dans une classe wrapper, la forme allouée dans le code de l'application, je ne pourrais pas gérer la forme la forme * renvoyée par les fonctions de la bibliothèque.



0
votes

Il y a beaucoup de solutions possibles, mais vous pouvez le faire, par exemple: Démarrer une nouvelle hiérarchie, qui rend les formes dans un contexte spécifique : xxx


1 commentaires

Certaines fonctions au sein de ma bibliothèque retourner les pointeurs / références à Forme . Par exemple, le composithape J'ai parlé d'avoir un ensemble de forme * qui peut être de quelque sorte. Donc, même si je garde dans une classe wrapper, la forme allouée dans le code de l'application, je ne pourrais pas gérer la forme la forme * renvoyée par les fonctions de la bibliothèque.



15
votes

Premier: "" Visiteur est un moyen de simuler une double dispatching en C ++. " 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 ++.


Si les opérations sur une hiérarchie de classe doivent être mises en œuvre par Ajout de fonctions virtuelles ou par ajout de visiteurs est déterminé par les probabilités d'ajouter des classes par rapport à l'ajout d'opérations:

  • Si le nombre de classes continue de changer plus rapidement que le nombre d'opérations, utiliser des fonctions virtuelles . En effet, l'ajout d'une classe nécessite de modifier tous les visiteurs.
  • Si le nombre le nombre de classes est relativement stable par rapport au nombre d'opérations, utilise les visiteurs . En effet, l'ajout d'une fonction virtuelle nécessite de changer toutes les classes de la hiérarchie.

    Oui, de nombreuses bibliothèques ne sont pas livrées avec une interface visiteur.
    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.

    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, la seule façon de le faire est d'ajouter un visiteur - si la bibliothèque fournit les crochets Pour eux de se brancher .
    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 .


2 commentaires

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 n'est-il pas votre visiteur quotidien de l'usine. Je suis désolé d'être si peu d'aide.



0
votes

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.

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.

Je n'aime pas les implémentations avec Visita, Visitb, Visuwayver, accepta, accepter, accepter. C'est absolument faux, imho.

Si vous avez une chance, veuillez consulter Un article que j'ai écrit à propos de ce .

C'est Java, mais vous pouvez passer à C ++ facilement si vous le trouvez utile à vos besoins.

J'espère que cela aide

acclamations


0 commentaires