03.20.08

Visitor Pattern : Elegance @ Work

Posted in Design Patterns, Java at 4:30 am by Administrator

Brief Background:

Visitor pattern arose from the need to handle different ‘kinds’ of data in a collection differently by some class; for example a list could have Strings, other Lists etc. In such a scenario; you’d end up writing instanceof checks (ugly); This example of handling different kinds of data in a collection might not be the best; but just bear with me for the moment. (I mention this different type thing because i will give a ‘generified Visitor pattern example in next post).



I believe in posting code and getting down to it; its like the source talks to me, saying all kinds of things that went in developer’s head while he was writing it. I had to strip Comments and javadocs out of this, because for some strange reason it seemed to break the post; I’ll post the files / project instead if someone asks for it.

Lets get on with it!

public interface IVisitable extends Serializable {

public void accept(IVisitor visitor);

}

The above is an interface for abstracting all visitable objects. A visitable object could be anything visitor ‘visits’; Typically vistable object (like a Destination for example) ‘accepts’ a visitor and calls visitor.visit(this) in accept method to delegate the responsibility of handling the logic for this visitation. (excuse the pun, i am a poor writer i guess).

public interface IVisitor extends Serializable {

public void visit(IVisitable visitable);

}

^^ A visitor interface that All visitors must implement. A visitor visits a ‘Visitable’ object (which in turn ‘accepts’ its visit) and calls this method to let the visitor handle business logic.

To understand and make it all concrete; lets consider a classic Transaction example; where we need to handle two types of transactions; viz. Deposit Transaction; Withdrawal Transactions. I could accomplish this without visitor off course (It turns and looks ugly and Not very OO apparently but it can work, as i will show below). In our example assume that Transaction is a IVisitable type given below.

@SuppressWarnings(”serial”)
public class Transaction implements IVisitable {

private Integer type;

public void accept(IVisitor visitor) {
visitor.visit(this);

}

public Integer getType() {
return type;
}

public void setType(Integer type) {
this.type = type;
}

@Override
public String toString() {
return “” + getType();

}
}

Next we implement two kinds of visitors (each for handling the type of transactions viz Deposit, Withdrawal).

@SuppressWarnings(”serial”)
public class DepositVisitor implements IVisitor {

public void visit(IVisitable visitable) {

System.out.println(” Performing a deposit on ” + visitable.toString());

}

}

Sounds naive, but hey! thats what my example tries to accomplish; elucidate concepts and not bloat the code.

@SuppressWarnings(”serial”)
public class WithdrawVisitor implements IVisitor {

public void visit(IVisitable visitable) {

System.out.println(” Performing withdrawal on ” + visitable.toString());
}

}

Next we create a visitor Factory which will be responsible for creating visitors; You will typically get hold of visitors using this. (I have not concentrated on making visitors singleton and other blah blah, i’ll leave that to you Java gurus out there).

public class VisitorFactory {

private static final Integer DEPOSIT = 100;
private static final Integer WITHDRAW = 200;

private static VisitorFactory visitorFactory;

private VisitorFactory(){
// Nothing here
}

public static VisitorFactory getInstance(){

if(visitorFactory == null){
visitorFactory = new VisitorFactory();

}

return visitorFactory;
}

public IVisitor getVisitor(IVisitable visitable){

IVisitor returnVisitor = null;

if(((Transaction)visitable).getType().compareTo(DEPOSIT) == 0){
returnVisitor = new DepositVisitor();

}else if(((Transaction)visitable).getType().compareTo(WITHDRAW) == 0){
returnVisitor = new WithdrawVisitor();

}else{

// default visitor
returnVisitor = new DepositVisitor();

}

// return
return returnVisitor;
}

}

Next; I illustrate the crux of the idea. I will first show how clean and flexible the code is, by showing A test case with VisitorPattern.

public class ConcreteTestWithVisitorPattern {

private static final Integer DEPOSIT = 100;
private static final Integer WITHDRAWAL = 200;

public static void main(String[] args) {
Transaction tx = new Transaction();
tx.setType(DEPOSIT); // SETTING TYPE AS DEPOSIT … NOTICE HOW CLEAN THIS CODE LOOKS
processTransaction(tx);

Transaction tx0 = new Transaction();
tx0.setType(WITHDRAWAL); // SETTING TYPE AS WITHDRAW … NOTICE HOW CLEAN THIS CODE LOOKS
processTransaction(tx0);

}

private static void processTransaction(Transaction tx) {
processTransaction(tx, VisitorFactory.getInstance().getVisitor(tx));
}

private static void processTransaction(Transaction tx, IVisitor visitor) {
tx.accept(visitor);
}

}

Notice that if i want to add another type of transaction visitor; i can do so easily (hook it up in factory) and delegate back to the same method. My ‘above code’ remains the same.

Now the Ugly code without the above pattern … =)

public class ConcreteTestWithoutVisitor {

private static final Integer DEPOSIT = 100;
private static final Integer WITHDRAWAL = 200;

public static void main(String[] args) {

Transaction tx = new Transaction();
processTransaction(tx);
}

public static void processTransaction(Transaction tx) {

if(tx.getType() == DEPOSIT){
System.out.println(” Do the deposit …”);

}else if(tx.getType() == WITHDRAWAL){
System.out.println(” Do the Withdrawal …”);

}

}

}

As you can make out it looks ugly; if i wanted to add another type of transaction; i’d have to add another if. While this is not such a strong example; it does show the concept of it. I can never imagine Wikipedia’s examples (they give a Car, Engine example) while it is a great example in every way; but i find it hard to directly apply the concept in daily work without the examples related to work i do. (thats the reason i hate Head First Design patterns book so much).

State Maintenance

I should point out however that wikipedia stresses an important point pretty well. In ‘visiting’ an IVisitable type; a visitor can maintain state of its previously visited IVisitable(s) and form a tree or graph of Nodes of sort. This can particularly useful if you want to form a tree structure and then modify the structure at a later stage to do some business process transformations.

More To follow : ‘Generics’ Version of the above.
Regards
Vyas, Anirudh

1 Comment »

  1. Programming Thoughts @ Work » A much better Strategy Pattern - Part II said,

    May 19, 2008 at 3:31 am

    […] and making it more flexible through Generics. ( For continuation purpose; here’s the link: Visitor Pattern - Part I. Speaking of generics, we can use Generics to improve the above code too … but thats for […]

Leave a Comment