web-dev-qa-db-fra.com

Différence entre le modèle de visiteur et la double répartition

Je lis sur le modèle de visiteur, et cela ressemble à Double Dispatch. Y a-t-il une différence entre les deux. Faire les deux termes signifie la même chose.

référence: http://www.vincehuston.org/dp/visitor.html

48
vamsi

En bref

ils proviennent de différentes conceptualisations qui, dans certaines langues où la double diffusion n'est pas prise en charge de manière native, conduisent au modèle de visiteur comme un moyen de concaténer deux (ou plus) distribution unique afin d'avoir un substitut à plusieurs diffusions.

En long

L'idée de la répartition multiple est - essentiellement - de permettre un appel comme

void fn(virtual base_a*, virtual base_b*); (note: pas en tant que membre de la classe: ce n'est PAS C++!)

qui peut être remplacé par

void fn(virtual derived_a1*, virtual derived_b1*);
void fn(virtual derived_a2*, virtual derived_b1*);
void fn(virtual derived_a1*, virtual derived_b2*);
void fn(virtual derived_a2*, virtual derived_b2*);

de sorte que, lors de l'appel

fn(pa, pb)

l'appel est redirigé vers le remplacement qui correspond au type d'exécution des deux pa et pb. (Vous pouvez généraliser cela à n'importe quel nombre de paramètres)

Dans un langage comme C++, C #, Java, ce mécanisme n'existe pas et la répartition du type d'exécution fonctionne essentiellement avec un seul paramètre (qui, étant un seul, est rendu implicite dans la fonction en rendant la fonction elle-même membre de la classe:

en d'autres termes, le pseudocode

void fn(virtual base_a*, base_b*) 

devient le (vrai C++)

class base_a
{
public:
    virtual void fn(base_b*);
}

Notez qu'il n'y a plus de virtual devant base_b, Qui est désormais statique. Un appel comme

pa->fn(pb) si pa pointe vers un dérivé_a2 et pb vers un dérivé_b1 sera distribué vers dérivé_a2 :: fn (base_b *), peu importe s'il y a dérivé_a2 :: fn (dérivé_b1 *) là-dedans: la course -type d'heure de l'objet pointé par pb n'est pas pris en compte.

L'idée du visiteur est que vous appelez l'envoi virtuel d'un objet qui appelle (éventuellement en retour) l'envoi virtuel d'un autre:

class base_a
{
public:
   virtual void fn(base_b*)=0;
   virtual void on_visit(derived_b1*)=0;
   virtual void on_visit(derived_b2*)=0;
};

class base_b
{
public:
   virtual void on_call(derived_a1*)=0;
   virtual void on_call(derived_a2*)=0;
};

//forward declarations, to allow pointers free use in other decls.
class derived_a1;
class derived_b1;


class derived_a1: public base_a
{
public:
   virtual void fn(base_b* pb) { pb->on_call(this); }
   virtual void on_visit(derived_b1* p1) { /* useful stuff */ }
   ...
};

class derived_b1: public base_b
{
public:
  virtual void on_call(derived_a1* pa1) { pa1->on_visit(this); }
  ... 
};

maintenant, un appel comme pa->fn(pb), si pa pointe sur dérivé_a1 et pb sur dérivé_b1, ira finalement à derived_a1::on_visit(derived_b1*).

41
Emilio Garavaglia

Le modèle de visiteur est une solution qui implémente le comportement de double répartition. Il peut également y avoir plusieurs autres solutions. Le terme double dispatch lui-même ne donne aucune idée de solution, en fait c'est un problème dont la solution est fournie par modèle de visiteur .

En C # (4.0), on pourrait utiliser le mot clé dynamic pour implémenter la double répartition, auquel cas le modèle de visiteur n'est pas requis. Voici ma solution au problème de double répartition en utilisant le mot clé dynamic:

13
Nawaz

Dynamic Dispatch fait référence au concept de répartition vers une méthode basée sur les informations d'exécution, en général. La plupart des systèmes OO (comme dans Java/C #/C++) implémentent généralement la répartition dynamique via les méthodes virtual (que toutes les méthodes soient ou non virtuelles dépendent du langage); cela les restreint à distribuer selon un seul argument de méthode (la référence d'objet implicite).

En général, vous pourriez vouloir répartir selon un nombre arbitraire d'éléments. La double répartition, par exemple, est l'exigence/la capacité de répartir selon deux arguments de la méthode.

En revanche, le modèle de visiteur est un implémentation de Multi Dispatch en général et donc de Double Dispatch en particulier dans de tels = OO systèmes.

5
Matthieu M.

La double expédition est un problème technique qui peut, selon la langue, être résolu de différentes manières - certaines langues prennent directement en charge la double expédition. Le modèle de visiteur est un modèle qui peut être utilisé pour résoudre différents problèmes. Dans le cas de C++, c'est la solution la plus fréquente (mais pas la seule) utilisée pour la double répartition, mais elle n'est pas utilisée exclusivement pour cela, et elle peut être utile même dans les langages qui prennent en charge la double répartition.

3
James Kanze

De Wikipedia :

le modèle de visiteur simule la double répartition dans un langage orienté objet classique à répartition unique tel que Java, Smalltalk et C++.

Aussi de Wikipedia :

Le problème décrit ci-dessus peut être résolu en simulant la double répartition, par exemple en utilisant un modèle de visiteur.

1
Peter Wood