访问者设计模式中的方法命名

时间:2013-12-09 03:02:30

标签: design-patterns

这是访问者设计模式的上下文/示例代码。

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

3 个答案:

答案 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机制。