Monday, January 15, 2007

Implementing Visitor Pattern in Java

The Visitor design pattern provides a way to separate algorithms from the object structure. A consequence of this separation is the ability to add new operations to existing object structures without modifying those structures. In design patterns, the authors define the Visitor Pattern as
Represent an operation to be performed on the elements of an object structure.
Visitor lets you define a new operation without changing the classes
of the elements on which it operates.

Skip to Sample Code

The idea is to have two class hierarchies
  1. One for the elements being operated on, where each element has an "accept" method that takes a visitor object as an argument
  2. One for the visitors that define operations on the elements. Each visitor has a visit() method for each element class.
The accept() method of the element class calls back the visit() method passing itself as an argument. Here is the UML diagram for the Visitor Pattern, followed by a brief description of the actors involved.Visitor Pattern UML
  • Visitor: Declares the visit method.
  • ConcreteVisitor: An implementation of the Visitor interface. May also store state if required.
  • Element (or Visitable): The interface that declares the accept method. The accept method invokes the visit method passing itself as an argument.
  • ConcreteElement: Element of the object structure. Has to implement accept method (implements Element).

When to Use
Use the Visitor pattern when
  1. There is a need perform operations that depend on concrete classes of an object structure, and the structure may contain classes of objects with differing interfaces.
  2. Distinct and unrelated operations must be performed on objects in an object structure, and you want to avoid distributing/replicating similar operations in their classes
  3. The classes defining the object structure rarely change, but new operations may be added every once in a while.

Pros and Cons
  • Easy to add new operations: To add a new operation, you only have to add a new Visitor implementation. There is no need to change the element classes.
  • Gather related operations: Visitor pattern helps gather related operations into the visitor, while the unrelated behavior is implemented in the individual elements.
  • Visiting across class hierarchies: Unlike iterators, visitors may visit objects in an object structure which need not have objects of the same type.
  • State Management: Visitors can keep track of state changes with each visit. Without a visitor, state has to be passed as an argument.
  • Hard to add new concrete elements: Adding a ConcreteElement involves adding a new operation to the Visitor interface and a corresponding implementation in each concrete visitor implementation. Visitor pattern is best used in cases where the object structure is stable but the set of operations may change frequently.
  • Breaking Encapsulation: Visitor pattern often forces you to provide public operations to access the internal state of the elements, which compromises encapsulation.

Visitor Pattern and Double Dispatch
Double dispatch is a mechanism that allows a function call to change depending on the runtime types of multiple objects involved in the call. In single dipatch a call like Integer.compareTo(Object o), the actual function call depends only on the calling object (the Integer object here). In double dispatch, the actual call may also depend on the object being passed as a parameter to the compareTo method.
The most common programming languages (except for LISP) do not have a way for implementing double dispatch. But you may implement double dispatch in these programming languages using the Visitor pattern. You can see the implementation in the following example. Here the call to accept depends not only on the type of object on which it is called (MyLong or MyInteger) but also on the parameter that is being passed to it (AddVisitor and SubtractVisitor).
package visitor;

interface Visitor {
public int visit(MyInteger wheel);

public int visit(MyLong engine);
}

interface Visitable {
public int accept(Visitor visitor);
}

class MyInteger implements Visitable {
private int value;

MyInteger(int i) {
this.value = i;
}

public int accept(Visitor visitor) {
return visitor.visit(this);
}

public int getValue() {
return value;
}
}

class MyLong implements Visitable {
private long value;

MyLong(long l) {
this.value = l;
}

public int accept(Visitor visitor) {
return visitor.visit(this);
}

public long getValue() {
return value;
}
}

class SubtractVisitor implements Visitor {
int value;

public SubtractVisitor(int value) {
this.value = value;
}

public int visit(MyInteger i) {
System.out.println("Subtract integer");
return (i.getValue() - value);
}

public int visit(MyLong l) {
System.out.println("Subtract long");
return ((int) l.getValue() - value);
}

}

class AddVisitor implements Visitor {
int value;

public AddVisitor(int value) {
this.value = value;
}

public int visit(MyInteger i) {
System.out.println("Adding integer");
return (value + i.getValue());
}

public int visit(MyLong l) {
System.out.println("Adding long");
return (value + (int) l.getValue());
}

}

public class VisitorTest {
public static void main(String[] args) {
AddVisitor cv = new AddVisitor(10);
SubtractVisitor sv = new SubtractVisitor(10);
MyInteger i = new MyInteger(20);
MyLong l = new MyLong(20);
System.out.println(i.accept(cv));
System.out.println(l.accept(cv));

System.out.println(i.accept(sv));
System.out.println(l.accept(sv));

}
}
VisitorTest.java

6 comments:

  1. Thanks for this tutorial, I found that this is the simplest Visitor Pattern explanation but also the easiest to understand.

    ReplyDelete
  2. You have copied all your articles from various books. The only difference I see here are the examples. Try to create better blogs where you can put in your own words

    ReplyDelete
  3. Oh,I know that this article very good, and the easiest to understand. That good for newbie, whom newcomer to java programming...
    Thank !

    ReplyDelete
  4. At Least ,HE is doing something valuable by sharing knowledge.....Good Work...

    ReplyDelete
  5. Why somebody is interested in finding out that this article is copied out from somewhere? Only see importance of the article. Very Easy to Understand.

    ReplyDelete
  6. My implementation of the visitor pattern:

    public interface CalculatorElement {
    void accept(CalculatorVisitor visitor);
    }

    public class Minus implements CalculatorElement{

    int val1 = 10;
    int val2 = 5;
    public int getVal1() {
    return val1;
    }
    public void setVal1(int val1) {
    this.val1 = val1;
    }
    public int getVal2() {
    return val2;
    }
    public void setVal2(int val2) {
    this.val2 = val2;
    }
    @Override
    public void accept(CalculatorVisitor visitor) {
    visitor.visit(this);
    }

    }

    public class Plus implements CalculatorElement{

    int val1 = 7;
    int val2 = 10;
    public int getVal1() {
    return val1;
    }
    public void setVal1(int val1) {
    this.val1 = val1;
    }
    public int getVal2() {
    return val2;
    }
    public void setVal2(int val2) {
    this.val2 = val2;
    }
    @Override
    public void accept(CalculatorVisitor visitor) {
    visitor.visit(this);
    }

    }



    public interface CalculatorVisitor {
    void visit(Object obj);
    }


    public class DoCalculate implements CalculatorVisitor {

    @Override
    public void visit(Object obj) {
    if (obj instanceof Minus) {
    Minus min = (Minus) obj;
    System.out.println("Minus: " + (min.getVal1() - min.getVal2()));
    }
    if (obj instanceof Plus) {
    Plus min = (Plus) obj;
    System.out.println("Plus: " + (min.getVal1() + min.getVal2()));
    }
    }
    }


    public class Worker {


    public static void main(String[] args) {
    Minus min = new Minus();
    min.accept(new DoCalculate());

    Plus plus = new Plus();
    plus.accept(new DoCalculate());
    }

    }

    ReplyDelete

Popular Posts