50

我正在阅读有关访问者模式的信息,它看起来与 Double Dispatch 相同。两者有没有区别。做这两个词的意思是一样的。

参考: http: //www.vincehuston.org/dp/visitor.html

4

5 回答 5

45

简而言之

它们来自不同的概念化,在某些本地不支持双重分派的语言中,导致访问者模式作为连接两个(或更多)单一分派的一种方式,以获得多分派代理。

在长

多重调度的想法 - 本质上 - 允许像

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

于 2012-03-22T07:40:46.417 回答
15

访问者模式是一种实现双重调度行为的解决方案。也可以有其他几种解决方案。术语双重调度本身并没有给出任何解决方案的概念,实际上它是一个由访问者模式提供解决方案的问题。

在 C# (4.0) 中,可以使用dynamic关键字来实现双重调度,在这种情况下不需要访问者模式。这是我使用关键字解决双重调度问题的方法:dynamic

于 2012-03-22T07:40:21.033 回答
5

一般来说,动态分派是指基于运行时信息分派给方法的概念。大多数 OO 系统(如在 Java/C#/C++ 中)通常通过virtual方法实现动态调度(是否所有方法都是虚拟的,取决于语言);这限制了它们根据单个方法参数(隐式对象引用)进行调度。

一般来说,您可能希望根据任意数量的元素进行调度。例如,双重分派是根据方法的两个参数分派的要求/能力。

另一方面,访问者模式通常是 Multi Dispatch 的实现,因此特别是在此类 OO 系统中的 Double Dispatch。

于 2012-03-22T08:09:47.007 回答
3

双分派是一个技术问题,根据语言的不同,可以用不同的方式解决——有些语言直接支持双分派。访问者模式是一种可用于解决不同问题的模式。在 C++ 的情况下,它是最常用的(但不是唯一的)用于双重分派的解决方案,但它并非专门用于此目的,即使在支持双重分派的语言中也很有用。

于 2012-03-22T09:06:49.510 回答
1

来自维基百科

访问者模式在传统的单分派面向对象语言(如 Java、Smalltalk 和 C++)中模拟双分派。

也来自维基百科

上述问题可以通过模拟双重调度来解决,例如使用访问者模式。

于 2012-03-22T08:07:50.730 回答