Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
293 views
in Technique[技术] by (71.8m points)

Difference betwen Visitor pattern & Double Dispatch

I am reading about visitor pattern, and it appears the same like Double Dispatch. Is there any difference between the two. Do the two terms means the same thing.

reference: http://www.vincehuston.org/dp/visitor.html

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In short

they come from to different conceptualizations that, in some languages where double dispatch is not natively supported, lead to the visitor pattern as a way to concatenate two (or more) single dispatch in order to have a multi-dispatch surrogate.

In long

The idea of multiple dispatch is - essentially - allow a call like

void fn(virtual base_a*, virtual base_b*); (note: not as a class member: this is NOT C++! )

that can be overridden as

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

so that, when calling

fn(pa, pb)

the call is redirected to the override that matches the actual runtime type of both pa and pb. (You can generalize this to whatever number of parameters)

In language like C++, C#, Java, this mechanism does not exist and runtime type dispatching basically works with just one parameter (that, being just one, is made implicit in the function by making the function itself member of the class:

in other words, the pseudocode

void fn(virtual base_a*, base_b*) 

becomes the (real C++)

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

Note that here there is no more virtual in front of base_b, that from now is static. A call like

pa->fn(pb) if pa points to a derived_a2 and pb to a derived_b1 will be dispatched to derived_a2::fn(base_b*), no matter if there is a derived_a2::fn(derived_b1*) in there: the run-time type of the object pointed by pb is not taken into account.

The idea of the visitor patter is that you call the virtual dispatch of an object that calls (eventually back) the virtual dispatch of another:

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

now, a call like pa->fn(pb), if pa points to derived_a1 and pb to derived_b1, will finally go to derived_a1::on_visit(derived_b1*).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...