2013-12-09 45 views
3

这里的游客设计模式的背景下/示例代码。方法命名

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

我也想知道这个答案,因为我同意你的看法。我从来没有见过这样做的实现。除了笨拙地阅读,我觉得有方法名称反映你正在访问的抽象是很奇怪的。这些参数包含在内。 – Vidya

+0

@Vidya然后投票赞成:D – xiamx

+0

完成。让我们看看发生了什么。 – Vidya

回答

3

约翰·弗利赛德斯的书模式孵化(GOF的作家之一,他的书有时被认为是一种补充设计模式)解释这两者的优势,以实现访客两种方式。

他说,使用不同的变量名的原因是这样的:

了较大幅度的优势是当有一个resonalbe默认行为,和子类往往忽略短短的操作。当我们超载时,子类必须覆盖的所有的功能;否则你友好的C++编译器可能会抱怨你的选择性覆盖隐藏了一个或多个基类操作。当我们为访客操作提供不同的名称时,我们会解决这个问题。然后子类可以不受惩罚地重新定义一部分操作。 - 图案孵化p.36

+0

谢谢,这听起来像一个很好的论点。这是C++编译器独有的“特性”还是OO语言(C#,java)中的一般行为? – xiamx

+0

我相信这是C++的特定行为。对于Java,根据JLS§9.4.1:在逐个签名的基础上覆盖方法。 '例如,如果一个接口声明两个具有相同名称的公共方法(第9.4.2节),并且子接口覆盖其中一个,则该子接口仍然继承另一个方法。 ' – dkatzel

0

四人帮,也就是模式圣经,按照你的教官的建议。

访问类定义应该像在C++:

class Visitor { 
public: 
    virtual void VisitElementA(ElementA*); 
    virtual void VisitElementB(ElementB*); 

    // and so on for other concrete elements 
protected: 
    Visitor(); 
}; 

结案。

查看我在@ vadya的回答上述观点:超载暗示方法做同样的事情,但支持的东西在不同的类型,这是不符合观众的情况。

+0

这背后的理由是什么?我可以在教科书中找到使用重载的例子,但这并不能回答我的问题。 – xiamx

+0

我想说如果你认为“四人帮”是错的,你需要提供理由。我通常尽量避免在类型是param的方法中提及类型,但我认为在这种情况下它确实有意义,因为访问者的整个想法就是所有在任何地方都能做的事情的方法。 – Rob

+0

我喜欢Go4和设计模式的想法,就像下一个人一样,但是盲目而虔诚地接受某些东西毫无疑问是任何事情中的一个糟糕主意。此外,OP并没有说Go4是“错误的”。他在问为什么他的想法也无法工作。这比黑白的正确或错误问题更细致。我们不要忘记来自欧比旺的伟大[课程](http://www.youtube.com/watch?v=wgpytjlW5wU)。 – Vidya

0

按我的理解Visitor设计模式的目的是解决单一问题调度的问题。 访问者模式提供双重分派方法。动态分派仅基于调用对象的类型,只有使用覆盖而不是超载才能实现。 使用重载将让函数依赖于调用期间传递的参数,我们不想在访问者中使用它。

使用重载超载以上的整个概念是实现访客双调度机制。

+1

“动态调度只基于调用对象的类型,只能使用覆盖而不是重载”<不正确 – xiamx

+0

按照我的理解动态调度机制是我们所说的运行时多态性,它在运行时被解析,而重载是一个编译如果你能给我提供一些例子来证明错误的说法,这对我来说是一个很大的帮助,并且可以改进这个概念,但是这对于动态调度是不可能的。 –