我正在阅读有关访问者模式的信息,它看起来与 Double Dispatch 相同。两者有没有区别。做这两个词的意思是一样的。
参考: http: //www.vincehuston.org/dp/visitor.html
我正在阅读有关访问者模式的信息,它看起来与 Double Dispatch 相同。两者有没有区别。做这两个词的意思是一样的。
参考: http: //www.vincehuston.org/dp/visitor.html
它们来自不同的概念化,在某些本地不支持双重分派的语言中,导致访问者模式作为连接两个(或更多)单一分派的一种方式,以获得多分派代理。
多重调度的想法 - 本质上 - 允许像
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*)
。
访问者模式是一种实现双重调度行为的解决方案。也可以有其他几种解决方案。术语双重调度本身并没有给出任何解决方案的概念,实际上它是一个由访问者模式提供解决方案的问题。
在 C# (4.0) 中,可以使用dynamic
关键字来实现双重调度,在这种情况下不需要访问者模式。这是我使用关键字解决双重调度问题的方法:dynamic
一般来说,动态分派是指基于运行时信息分派给方法的概念。大多数 OO 系统(如在 Java/C#/C++ 中)通常通过virtual
方法实现动态调度(是否所有方法都是虚拟的,取决于语言);这限制了它们根据单个方法参数(隐式对象引用)进行调度。
一般来说,您可能希望根据任意数量的元素进行调度。例如,双重分派是根据方法的两个参数分派的要求/能力。
另一方面,访问者模式通常是 Multi Dispatch 的实现,因此特别是在此类 OO 系统中的 Double Dispatch。
双分派是一个技术问题,根据语言的不同,可以用不同的方式解决——有些语言直接支持双分派。访问者模式是一种可用于解决不同问题的模式。在 C++ 的情况下,它是最常用的(但不是唯一的)用于双重分派的解决方案,但它并非专门用于此目的,即使在支持双重分派的语言中也很有用。