访客模式

时间:2017-11-11 17:51:56

标签: java visitor visitor-pattern

我正在查看访问者模式here的说明,其中显示了以下代码:

public class ShoppingCart {
  public double calculatePostage() {
    PostageVisitor visitor = new PostageVisitor();
    for(Visitable item: items) {
      item.accept(visitor);
    }

public class PostageVisitor implements Visitor {
  public void visit(Book book) {

public class Book implements Visitable{
  public void accept(Visitor vistor) {
    visitor.visit(this);
  }

从JavaScript开发人员的角度来看,accept方法似乎是多余的,因为代码可以写成:

for(Visitable item: items) {
   // directly call visitor passing an item instead of doing so through `accept` method
   visitor.visit(item);  
}

我是否正确地认为这不起作用,因为编译器不知道访问者执行哪个重载visit方法?

据我所知,编译器了解visit使用visitor执行哪个accept方法,因为它可以匹配传递给this的{​​{1}}类型这里的方法:

visitor.visit(this)

修改

刚刚发现除了这里的好答案this answer之外,还提供了很多有用的细节。

2 个答案:

答案 0 :(得分:4)

  

我是否正确地认为这不会起作用,因为编译器不知道访问者执行哪种重载访问方法?

绝对。访问者是双重发送; accept执行调度的第一站,因为它在item上是虚拟的。 accept内的代码通过让编译器选择正确的重载来执行调度的第二段。

  

据我所知,编译器了解哪个访问方法在访问者上执行,因为它可以匹配传递给visitor.visit(this)的访问者的类型

这是完全正确的。我认为在访问者的这个实现中令人困惑的部分是过载。更容易看到发生了什么,而不是重载visit,你给每个重载一个单独的名称。换句话说,而不是

public void visit(Book book);
public void visit(Cow cow);
public void visit(Island island);
你写了

public void visitBook(Book book);
public void visitCow(Cow cow);
public void visitIsland(Island island);

答案 1 :(得分:2)

  

从JavaScript开发人员的角度来看,accept方法似乎是多余的,因为代码可以这样编写:

for(Visitable item: items) {
    // directly call visitor passing an item instead of doing so through `accept` method
    visitor.visit(item);  
}

代码无法像JavaScript那样编写。要了解原因,让我们先来看看访客的样子。在Java中,它看起来像这样:

void visit(Book book) { ... }
void visit(OtherThing otherThing) {...}

JavaScript没有这样的重载,因此不同的访问方法需要不同的名称。所以它看起来会像这样:

function visitBook(book) { ... }
function visitOtherThing(otherThing) { ... }

现在你显然无法visitor.visit(item),因为没有visit方法。 visitBookvisitOtherThingacceptvisitBook,但您不知道要拨打哪个,因为您没有使用哪种类型的项目。所以你仍然需要一个接受方法。然后,图书的OtherThing方法会调用accept,而visitOtherThing的{​​{1}}方法会调用{{1}}。

事实上,这就是JavaScript中的访问者模式通常的样子。

  

我是否正确地认为这不起作用,因为编译器不知道访问者的哪个重载访问方法要执行?

  

据我所知,编译器了解在访问者上使用accept执行哪种访问方法,因为它可以匹配传递给visitor.visit(this)方法的类型

完全。