Подтвердить что ты не робот

Разница между шаблоном посетителя и двойной рассылкой

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

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

4b9b3361

Ответ 1

Короче

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

В длинном

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

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

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

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. (Вы можете обобщить это на любое количество параметров)

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

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

void fn(virtual base_a*, base_b*) 

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

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

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

pa->fn(pb), если pa указывает на производный_a2 и pb на производный_b1, будет отправлен output_a2:: fn (base_b *), независимо от того, существует ли в нем производный_a2:: fn (производный_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 указывает на производные_a1 и pb на производные_b1, наконец, перейдет к derived_a1::on_visit(derived_b1*).

Ответ 2

Шаблон посетителя - это одно из решений, которое реализует поведение двойной отправки. Могут быть и другие решения. Сам термин "двойная отправка" не дает никакого представления о решении, на самом деле это проблема, решение которой предоставляется шаблоном посетителя.

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

Из Wikipedia:

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

Также из Wikipedia:

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