Question

I do well master Visitor Pattern. However, I wonder something.

Most important motivation to use Visitor Pattern is to add logic involvingo specific Data Models in client side without needing to check for the real data object type. The technique used for solving is called Double-Dispatching.

So, here a code snippet of data model implementing an accept() method:

public class Ferrari extends Car {
    //......
    @Override
    public void accept(Visitor v){
      v.visit(this);
    }
  }

And here a PrintCarVisitor implementing Visitor interface:

public class PrintCarVisitor implements Visitor {
  //...
  @Override
  public void visit(Ferrari c){
    System.out.println("Ferrari");
  }
}

Hence, no if/else series and instanceof series needed.

Any client would be:

Visitor visitor = new PrintCarVisitor();
car.accept(visitor);  //no need to know the exact Car's type

However, since Visitor doesn't keep Open/Closed Principle (because a new Data Model leads to break the class by adding its own visit method), why do we bother with double-dispatching?

Can't we just isolate the if/else series WITHIN the visitor implementation.

With this hypothetical alternative, this part of code would disappear:

 public class Ferrari extends Car {
    //This method is not needed anymore with this alternative
    @Override
    public void accept(Visitor v){
      v.visit(this);
    }
  }

PrintCarVisitor would be:

public class PrintCarVisitor {
   public void visit(Car c){
     if(c instanceof Ferrari){
       System.out.println("Ferrari");
     }
   }      
}

With this alternative, every caller would still deal with data model abstraction like this:

new PrintCarVisitor().visit(car); //no need to know the exact data type in client side

A priori, this second approach is great since it doesn't involve all the boilerplate generates during implementation of pure Visitor Pattern.

I imagine this approach has two drawbacks:

1) There's no guarantee (like Visitor interface imposes) that any used visitor disposes of a method corresponding to the Car currently treated.

2) BoilerPlate code remains heavier into the Visitor implementation class with the series of instanceof and casting.

Are they any other drawbacks explaining why Visitor Pattern HAS TO use Double Dispatching and so can't simply isolate the instanceof series inside a class (as static Factory does for example)?

Was it helpful?

Solution

  1. If you do this, you no longer have a Visitor, you basically have some sort of processor. Your code would just be a list iteration where every time thru the loop, you pass what formerly used accept to the processor, which was formally the visitor. Instead of the visitor visiting the visited, you are in a sense inverting the paradigm; the visited becomes the visitor, since it is initially passed to the worker. You could do it; you wouldn't call it a Visitor though.

  2. Conventional wisdom usually dictates that use of instanceof should be reserved for last-resort. Why would you use instanceof, when you can let the polymorphism of Java do it for you? One of the points of having objects is this benefit. If you do this, why not eschew overriding methods and just use instanceof to determine what to do in a class's methods, instead of relying on dynamic dispatch, for the case of overriding methods?

OTHER TIPS

The Xtext project had the same problem and they created a helper class PolymorphicDispatcher. In a nutshell, PolymorphicDispatcher does at runtime what the compiler does at compile time: Find the method that matches a set of parameters best and invoke it.

So your visitor would look like:

 public class PrintCarVisitor {
   public void visit(Car c){
      System.out.println("Just a car");
   }
   public void visit(Ferrari c){
      System.out.println("A Ferrari!");
   }
 }

Here is the source.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top