Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the need for `accept` method in Visitor pattern

I'm looking at the explanation of the visitor pattern here which shows the following code:

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

From the standpoint of JavaScript developer the accept method seems redundant since the code could be written like this:

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

Am I right to assume that this won't work because the compiler doesn't know which overloaded visit method of the visitor to execute?

As I understand the compiler understands which visit method to execute on the visitor with accept since it can match the type of this passed to the visitor.visit(this) method here:

public void accept(Visitor vistor) {
    visitor.visit(this);
}

Edit:

Just found that in addition to the great answers here this answer also provides a lot of useful details.

like image 520
Max Koretskyi Avatar asked Nov 11 '17 17:11

Max Koretskyi


1 Answers

Am I right to assume that this won't work because the compiler doesn't know which overloaded visit method of the visitor to execute?

Absolutely. Visitor is for double-dispatch; accept executes the first leg of dispatch, because it is virtual on the item. The code inside accept executes the second leg of dispatch by letting the compiler pick the proper overload.

As I understand the compiler understands which visit method to execute on the visitor with accept since it can match the type of this passed to the visitor.visit(this)

This is exactly right. I think the part that is confusing in this implementation of the visitor is the overload. It is much easier to see what's going on when instead of overloading visit you give each overload a separate name. In other words, instead of

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

you write

public void visitBook(Book book);
public void visitCow(Cow cow);
public void visitIsland(Island island);
like image 162
Sergey Kalinichenko Avatar answered Sep 27 '22 22:09

Sergey Kalinichenko