访客模式中"accept"方法的需要是什么

Max*_*kyi 5 java visitor visitor-pattern

我期待在访问者模式的解释在这里,显示下面的代码:

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);
  }
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

public void accept(Visitor vistor) {
    visitor.visit(this);
}
Run Code Online (Sandbox Code Playgroud)

编辑:

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

das*_*ght 5

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

绝对地。访客为双重派遣accept执行调度的第一段,因为它在item. 内部代码accept通过让编译器选择适当的重载来执行调度的第二段。

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

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

public void visit(Book book);
public void visit(Cow cow);
public void visit(Island island);
Run Code Online (Sandbox Code Playgroud)

你写

public void visitBook(Book book);
public void visitCow(Cow cow);
public void visitIsland(Island island);
Run Code Online (Sandbox Code Playgroud)