访客模式与访客之间的差异双重发货

时间:2012-03-22 07:35:55

标签: design-patterns visitor double-dispatch

我正在阅读访客模式,它看起来像Double Dispatch。两者之间有什么区别吗? 这两个术语是否意思相同。

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

5 个答案:

答案 0 :(得分:41)

简而言之

它们来自不同的概念,在某些语言中,双重调度本身不受支持,导致访问者模式作为连接两个(或更多)单个调度的方式,以便具有多调度代理。 / p>

多次发送的想法 - 基本上 - 允许像

这样的调用

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)

将调用重定向到与papb的实际运行时类型匹配的覆盖。 (您可以将其概括为任意数量的参数)

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

答案 1 :(得分:13)

访客模式是一个解决方案,它实现了双重调度的行为。还可以有其他几种解决方案。术语 double dispatch 本身并不提供解决方案的任何想法,实际上这是一个问题,其解决方案由访客模式提供。

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

答案 2 :(得分:5)

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

通常,您可能希望根据任意数量的元素进行调度。例如,Double Dispatch是根据方法的两个参数分派的要求/能力。

另一方面,访客模式一般是Multi Dispatch的实现,因此特别是在这样的OO系统中是Double Dispatch。

答案 3 :(得分:3)

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

答案 4 :(得分:1)

来自Wikipedia

  

访问者模式模拟传统的单调度面向对象语言(如Java,Smalltalk和C ++)中的双重调度。

同样来自Wikipedia

  

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