这是访问者设计模式的上下文/示例代码。
public interface Visitable{
public void accept(Visitor v);
}
public class Book implements Visitable{
public void accept(Visitor v){
v.visit(this);
}
public void read() {}
/**
book stuff
**/
}
public class Movie implements Visitable{
public void accept(Visitor v){
v.visit(this);
}
public void watch() {}
/**
movie stuff
**/
}
public interface Visitor{
public void visit(Book b);
public void visit(Movie m);
}
public class Person implements Visitor{
public void visit(Book b){
b.read();
}
public void visit(Movie m){
m.watch();
}
}
我的导师说,重载visit
方法并不是一个好主意,我应该为每个访问方法提供一个不同的名称,如下所示。我不相信这个想法。有人可以解释重载visit
方法的缺点是什么吗?
public interface Visitor{
public void visitBook(Book b);
public void visitMovie(Movie m);
}
public class Person implements Visitor{
public void visitBook(Book b){
b.read();
}
public void visitMovie(Movie m){
m.watch();
}
}
答案 0 :(得分:4)
John Vlissides的书 Pattern Hatching (其中一位GOF作者和他的书有时被认为是设计模式的补充)解释了实现访问者的两种方式的优点。
他说使用不同变量名的原因是:
当存在resonalbe默认行为时,会产生更大的优势,而子类往往只会覆盖一些操作。当我们重载时,子类必须覆盖所有的函数;否则你友好的C ++编译器可能会抱怨你的选择性覆盖会隐藏一个或多个基类操作。当我们给访客操作差异名称时,我们会解决这个问题。然后,子类可以重新定义操作的子集而不受惩罚。 - 模式孵化p.36
答案 1 :(得分:0)
四人帮书,又名模式圣经,就像你的导师所说的那样。
在C ++中,Visitor类将被声明为这样:
class Visitor { public: virtual void VisitElementA(ElementA*); virtual void VisitElementB(ElementB*); // and so on for other concrete elements protected: Visitor(); };
案件结案。
请参阅上面关于@vadya的回答的观点:重载意味着方法做同样的事情,但是支持不同类型的东西,而访问者不是这种情况。
答案 2 :(得分:0)
根据我的理解,访客设计模式的目的是解决单一调度问题。 访客模式提供双重调度方法。动态分派仅基于调用对象的类型,只能使用覆盖而不是重载。 使用重载将使函数依赖于在调用期间传递的参数,这是我们在访问者中不想要的。
使用覆盖重载的整个概念是在访问者中实现Double Dispatch机制。