Разница между посетителем pattern & Double Dispatch

Я читаю о шаблоне посетителя, и он выглядит так же, как двойная отправка. Есть ли разница между ними? Два термина означают одно и то же.

ссылка:http://www.vincehuston.org/dp/visitor.html

5 ответов


короче

они исходят из разных концептуализаций, которые на некоторых языках, где двойная отправка изначально не поддерживается, приводят к шаблону посетителя как способ объединения двух (или более) одной отправки, чтобы иметь суррогат мульти-отправки.

на долго

идея множественной отправки-по существу-Разрешить вызов, как

void fn(virtual base_a*, virtual base_b*); (примечание: не как член класса: это не C++! )

это можно переопределить как

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*);

так, что при вызове

fn(pa, pb)

вызов перенаправляется на переопределение, которое соответствует фактическому времени выполнения типа как pa и pb. (Вы можете обобщить это на любое количество параметров)

на таких языках, как C++, C#, Java, этот механизм не существует, и диспетчеризация типов среды выполнения в основном работает только с одним параметром (который, будучи только одним, сделан неявно в функции, делая саму функцию членом класса:

другими словами, псевдокод

void fn(virtual base_a*, base_b*) 

становится (реальный C++)

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

обратите внимание, что здесь нет больше virtual перед base_b, это отныне статично. Звонок типа

pa->fn(pb) если pa указывает на derived_a2, а pb на derived_b1 будет отправлен в derived_a2::fn(base_b*), независимо от того, есть ли там derived_a2::fn (derived_b1*) : тип времени выполнения объекта, на который указывает pb, не учитывается.

идея посетителя болтовни заключается в том, что вы называете виртуальную отправку объекта, который вызывает (в конечном итоге обратно) виртуальную отправку другого:

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); }
  ... 
};

сейчас, как pa->fn(pb), если pa указывает на derived_a1 и pb на derived_b1, наконец, перейдет к derived_a1::on_visit(derived_b1*).


шаблон Visitor составляет один решение, которое реализует поведение двойной диспетчеризации. Может быть и несколько других решений. Термин двойной диспетчеризации сам по себе не дает никакого представления о решении, на самом деле это проблема, решение которой обеспечивается шаблон Visitor.

В C# (4.0), можно использовать dynamic ключевое слово для реализации двойной отправки, в этом случае шаблон посетителя не требуется. Вот мое решение двойной отправки


Динамическая Диспетчеризация относится к концепция диспетчеризации в метод, основанный на информации о времени выполнения, в целом. Большинство систем OO (как в Java/C#/C++) обычно реализуют динамическую отправку через virtual методы (независимо от того, являются ли все методы виртуальными, зависят от языка); это ограничивает их отправкой в соответствии с одним аргументом метода (неявная ссылка на объект).

В общем случае вы можете захотеть отправить в соответствии с произвольным число элементов. Например, двойная отправка-это требование / возможность отправки в соответствии с двумя аргументами метода.

С другой стороны,Шаблон Visitor - это реализация Multi отправки вообще и таким образом двойной отправки в частности в таких системах OO.


двойная отправка техническая проблема, которая может, в зависимости от языка, быть решена по-разному-некоторые языки поддерживают двойную отправку напрямую. Шаблон посетитель шаблон, который может быть использован для решения различных проблем. В случае c++ это наиболее частое (но не единственное) решение, используемое для двойной отправки, но оно не используется исключительно для этого, и оно может быть полезно даже в языках, которые поддерживают двойную отправку.


с Википедия:

шаблон посетителя имитирует двойную отправку на обычном объектно-ориентированном языке с одной отправкой, таком как Java, Smalltalk и C++.

и с Википедия:

проблема, описанная выше, может быть решена путем моделирования двойной отправки, например, с помощью шаблона посетителя.