I've been a zone leader with DZone since 2008, and I'm crazy about community. Every day I get to work with the best that JavaScript, HTML5, Android and iOS has to offer, creating apps that truly make at difference, as principal front-end architect at Avego. James is a DZone Zone Leader and has posted 639 posts at DZone. You can read more from them at their website. View Full User Profile

Design Patterns Uncovered: The Visitor Pattern

03.09.2010
| 100500 views |
  • submit to reddit

Today we're going to take a look at the Visitor pattern. Of all of the patterns that I've used so far, Visitor is by far the most powerful and convenient.  

Vistors in the Real World 

A real world analogy always helps with the understanding of a design pattern. One example I have seen for the Visitor pattern in action is a taxi example, where the customer calls orders a taxi, which arrives at his door. Once the person sits in, the visiting taxi is in control of the transport for that person. 

Shopping in the supermarket is another common example, where the shopping cart is your set of elements. When you get to the checkout, the cashier acts as a visitor, taking the disparate set of elements (your shopping), some with prices and others that need to be weighed, in order to provide you with a total. 

It's a difficult pattern to explain in the real world, but things should become clearer as we go through the pattern definition, and take a look at how to use it in code.  

Design Patterns Refcard
For a great overview of the most popular design patterns, DZone's Design Patterns Refcard is the best place to start. 

The Visitor Pattern

The Visitor is known as a behavioural pattern, as it's used to manage algorithms, relationships and responsibilities between objects. The definition of Visitor provided in the original Gang of Four book on Design Patterns states: 

Allows for one or more operation to be applied to a set of objects at runtime, decoupling the operations from the object structure. 

What the Visitor pattern actually does is create an external class that uses data in the other classes. If you need to perform operations across a dispate set of objects, Visitor might be the pattern for you. The GoF book says that the Visitor pattern can provide additional functionality to a class without changing it. Let's see how that can work, first by taking a look at the classic diagram definition of  the Visitor pattern:

The core of this pattern is the Visitor interface. This interface defines a visit operation for each type of ConcreteElement in the object structure. Meanwhile, the ConcreteVisitor implements the operations defined in the Visitor interface. The concrete visitor will store local state, typically as it traverses the set of elements. The element interface simply defines an accept method to allow the visitor to run some action over that element - the ConcreteElement will implement this accept method. 

Where Would I Use This Pattern?

The pattern should be used when you have distinct and unrelated operations to perform across a structure of objects. This avoids adding in code throughout your object structure that is better kept seperate, so it encourages cleaner code. You may want to run operations against a set of objects with different interfaces.  Visitors are also valuable if you have to perform a number of unrelated operations across the classes.

In summary, if you want to decouple some logical code from the elements that you're using as input, visitor is probably the best pattern for the job.

So How Does It Work In Java?

The following example shows a simple implementation of the pattern in Java. The example we'll use here is a postage system. Our set of elements will be the items in our shopping cart. Postage will be determined using the type and the weight of each item, and of course depending on where the item is being shipped to. 

Let's create a seperate visitor for each postal region. This way, we can seperate the logic of calculating the total postage cost from the items themselves. This means that our individual elements don't need to know anything about the postal cost policy, and therefore, are nicely decoupled from that logic. 

First, let's create our general visitable  interface: 

//Element interface
public interface Visitable
{
public void accept(Visitor visitor);
}

Now, we'll create a concrete implementation of our interface, a Book.

//concrete element 
public class Book implements Visitable
{
private double price;
private double weight;

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

public double getPrice()
{
return price;
}

public double getWeight()
{
return weight;
}
}

As you can see it's just a simple POJO, with the extra accept method added to allow the visitor access to the element. We could add in other types here to handle other items such as CDs, DVDs or games.


Now we'll move on to the Visitor interface. For each different type of concrete element here, we'll need to add a visit method. As we'll just deal with Book for now, this is as simple as: 

public interface Visitor
{
public void visit(Book book);
//visit other concrete items
public void visit(CD cd);
public void visit(DVD dvd);
}

The implementation of the Vistor can then deal with the specifics of what to do when we visit a book. 

public class PostageVisitor implements Visitor
{
private double totalPostageForCart;
//collect data about the book
public void visit(Book book)
{
//assume we have a calculation here related to weight and price
//free postage for a book over 10
if(book.getPrice() < 10.0)
{
totalPostageForCart += book.getWeight() * 2;
}
}

//add other visitors here
public void visit(CD cd){...}
public void visit(DVD dvd){...}
//return the internal state
public double getTotalPostage()
{
return totalPostageForCart;
}
}

As you can see it's a simple formula, but the point is that all the calculation for book postage is done in one central place. 

To drive this visitor, we'll need a way of iterating through our shopping cart, as follows: 

public class ShoppingCart
{
//normal shopping cart stuff
private ArrayList<Visitable> items;

public double calculatePostage()
{
//create a visitor
PostageVisitor visitor = new PostageVisitor();
//iterate through all items
for(Visitable item: items)
{
item.accept(visitor);
}
double postage = visitor.getTotalPostage();
return postage;

}


}

Note that if we had other types of item here, once the visitor implements a method to visit that item, we could easily calculate the total postage.

So, while the Visitor may seem a bit strange at first, you can see how much it helps to clean up your code. That's the whole point of this pattern - to allow you seperate out certain logic from the elements themselves, keeping your data classes simple.

Watch Out for the Downsides

The arguments and return types for the visiting methods needs to be known in advance, so the Visitor pattern is not good for situtations where these visited classes are subject to change. Every time a new type of Element is added, every Visitor derived class must be amended. 

Also, it can be difficult to refactor the Visitor pattern into code that wasn't already designed with the pattern in mind. And, when you do add your Visitor code, it can look obscure. The Visitor is powerful, but you should make sure to use it only when necessary.   

Other Articles in This Series
The Observer Pattern
The Adapter Pattern
The Facade Pattern
The Factory Method Pattern
The Abstract Factory Pattern
The Singleton Pattern
The Strategy Pattern
The Visitor Pattern

Next Up

Later on this week, we're going to visit the Proxy pattern

Tags:

Comments

Slava Lo replied on Tue, 2010/03/09 - 7:05am

With visitor pattern, do we really need to define 'accept' method on the Element/Item class that will be visited? 

We could easily call visitor.visit(item) directly instead of making delegated call via item.accept(visitor).

 Am I missing something here ?

Yaozong Zhu replied on Tue, 2010/03/09 - 7:31am

I have the same concern as Slava's. What's the accept method for? Without it, the item will be a genuine element POJO.

Andy Leung replied on Tue, 2010/03/09 - 8:37am

Same here, now Book becomes so tightly coupled.

James Sugrue replied on Tue, 2010/03/09 - 8:59am in response to: Slava Lo

Good to see some discussion around the pattern. I think that in the case of the example above, what you say is true. But if we wanted to decide inside our Item class whether or not it should participate in any visiting, we would have extra logic around the accept(Visitor vistor) method.

For example, if we have books that are free and we never want any visitor to drop by.

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

But I do agree, with Visitor you have a level of coupling that you might not have wanted. Again, before you use the pattern, you need to be sure it fits. 

 

Erin Garlock replied on Tue, 2010/03/09 - 9:16am

Perhaps a second, slightly more complex, example will shed some light on the visitor.  There is a pretty good example at wikipedia that shows a visitor that understands how to operate on a set of classes.

http://en.wikipedia.org/wiki/Visitor_pattern

James' section in this article, "Where Would I use this Pattern?" states exactly what the CarElementPrintVisitor class does in the wikipedia article.

 To make the PostageVisitor implementation cleaner, line 15 should probably say something like:

//Add other objects to visit here
public void visit(CD cd)...
public void visit(DVD dvd)...

 

Magnus Smith replied on Tue, 2010/03/09 - 9:55am

Might be better to rename the CartItem interface the Visitable interface as this would be a little more suggestive...

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

Having the accept method callback to the visitor delegates the computational task (calculate postage) that we wish to achieve away from the object (book).  This may be a very good thing.  Books probably shouldn't need to be concerned about postage and this way if the way postage is calculated changes in the future then the book is unnaffected by the change. 

It can lead to tightly coupled system if used without much thought to seperating concerns between the object and the visitor.

 

Alex Miller replied on Tue, 2010/03/09 - 10:03am

You might find my entry on Visitor variations to be a good complement to this article: http://tech.puredanger.com/2007/07/16/visitor/.

James Sugrue replied on Tue, 2010/03/09 - 10:40am in response to: Magnus Smith

Good suggestion - I've gone ahead and made that change.

James Sugrue replied on Tue, 2010/03/09 - 10:43am in response to: Alex Miller

Nice article Alex - very comprehensive

James Sugrue replied on Tue, 2010/03/09 - 10:45am in response to: Erin Garlock

Thanks Erin - I've updated the visitor to include those methods.

You're right, it does make things clearer.

Bob Santos replied on Tue, 2010/03/09 - 6:22pm

Very good take on another pattern.:) I think you forgot to replace CartItem in the ShoppingCart class.

John Ericksen replied on Tue, 2010/03/09 - 8:50pm

I've always found this pattern to be a very handy way to handle a wide varieity of object oriented issues (tree navigation, subclassing / instanceof avoidance, etc).  One elaboration on the pattern we made at my work was to give the Visitor a parameterized return value.  So the visitor interface would look like this, using your examples:

public interface ReturningVisitor<T>
{
T visit(Book book);
//visit other concrete items
T visit(CD cd);
T visit(DVD dvd);
}

with an accept method as follows:

public interface Visitable
{
<T> T accept(ReturningVisitor<T> visitor);
}

and

public <T> T accept(Visitor<T> vistor)
{
return visitor.visit(this);
}

All together this allows you to return in-line values from your visitor accept method like so:

double postage = book.accept(new PostageVisitor());

where PostageVisitor is defined as:

public class PostageVisitor implements ReturningVisitor<Double>
{

public Double visit(Book book)
{
return book.getWeight() * 2;
}

//other visit methods...
}

This style of visitor can be defined along side the typical Visitor to allow you to create both the parameterized returning Visitor as well as Visitors that return void like so:

public interface Visitable
{
<T> T accept(ReturningVisitor<T> visitor);

void accept(Visitor visitor);
}

 

Manjuka Soysa replied on Tue, 2010/03/09 - 9:38pm

I've used this pattern (or a variation) where common pieces of functionality needs to be done before or after varying pieces of functionality.

So the accept method would be like :


public void accept(Visitor v)
{
// pre-processing eg. start a transaction
this.startTransaction();

v.visit(this);

// post processing
this.commitTransaction();
}

Now with containers and AOP this is not a good example, but you get the idea!

Tiehie Tiehie Nog replied on Mon, 2010/03/22 - 10:20am

We want the Proxy pattern! :)

Claudiu Dumitrescu replied on Wed, 2010/03/24 - 7:38am

Another usecase I can think of, where this pattern could be applied, is when you need to add new operations based on private field/operations of the class. For example calculate the discount using the realPrice field of the book. Ofcourse, the visit method would accept as parameter an integer rather than the book object.

Ali Ok replied on Tue, 2010/03/30 - 7:52am

An example usage of this pattern is, Swing's JFileChooser.

JFileChooser visits user defined FileFilter for each file, to determine whether display the file or not.

Example below shows only txt files on FileChooser.

        JFileChooser chooser = new JFileChooser();
chooser.setFileFilter(new FileFilter() {

@Override
public String getDescription() {...}

@Override
public boolean accept(File f) {
if(f.getName().endsWith(".txt"))
return true;
return false;
}
});

 

Richard Gomes replied on Sat, 2011/01/29 - 5:43pm

Hi,

Researching this subject I've learned that there are several flavors of the Visitor Pattern.

In particular, I don't like implementations which contain several visitA, visitB, visitWhatever, acceptA, acceptB, acceptWhatever. So, I designed a clean way to keep the original pattern and separate the concern of polymorphism in a pair of auxiliar interfaces. 

I've written an article about this subject which may be of your interest.

Thanks,

 

Richard Gomes
http://www.jquantlib.org/index.php/User:RichardGomes

Carlos Sierra replied on Sat, 2011/03/19 - 6:01pm in response to: Slava Lo

As far as I know visitor pattern is intented to work over a list of different items that not necessarily have a common ancestor.

 In the case you are detailing -> visitor.visit(item), if you have a list of items they must share a common ancestor for you to be able to traverse them, say Object or, if you prefer Item:

<code>

for (Item item : List<Item>) {

  visitor.visit(item)

}

</code>

as you may know, methods in Java (and I guess in other languages) are resolved at "compile time" (I don't know whether this is the correct way to call this). This means that no matter how many different methods you have in your visitor interface, only the method with signature visit (Item item) is going to be called in a loop like the one I described before. Moreover, compiler will claim if your visitor does not implement a method visit (Item).

So IMHO the purpose of the delegated call via accept is twofold: on one hand you have your common ancestor set to Visitable<V>, which is the interface that is defining the accept method and, on the other hand, you are circumventing static types method resolving because the Visitable always call the Visitor using "this":

<code>

public void accept(Visitor visitor) {

   visitor.visit(this);

</code>

as you can see this ensures you are always invoking the most concrete method of Visitor.

This, together with an AbstractVisitor that implemented all the methods for all the concrete types and routed them to a method such as:

<code>

abstract class DefaultVisitorImpl {

  public void visit(ConcreteItem item) {

     this.visitUnknown(item);

  }

  etc... etc...

  public abstract visitUnknown(Visitable item);

}

</code>

Allows you to implement a Visitor for a concrete item, no matter that the number of elements grow in time provided that both Visitor and DefaultVisitorImpl are maintained accordingly. These two classes may very well be provided by a library vendor or the like.

So in the loop we looked at at first would be:

<code>

Visitor visitor = new DefaultVisitorImpl {

   //your code here for processing the Concrete Visitables

   public void visitUnknown(Visitable item) {

      // Error, nothing at all, what you want to do whith unknown

   }

}

for (Visitable visitable: List<Visitable>) {

   visitable.accept(visitor);

}

</code>

and everything should work as expected. 

 Hope this helps.

Daniel Wright replied on Mon, 2011/05/02 - 2:12pm in response to: Richard Gomes

Richard your article is very interesting.
I found another article describing an interesting way of implementing the Visitor pattern using Generics
Daniel

Bruno Feurer replied on Fri, 2012/01/06 - 5:27am

Since the visitor pattern (double dispatch) also has it's drawbacks, I have compared different ways to implement simple multi-methods in Java: http://choosle.ch/Dczz Maybe my findings can help others as well (you can ignore, weight the different factors).

Fredrik Liden replied on Wed, 2013/12/18 - 3:35pm

I guess you might as well have an abstract implementation of Visitable and put the accept methods in that one instead of having to copy and paste them into all the Visitable implementations.

Darren Martin replied on Sun, 2014/03/16 - 11:44pm

 But I guess that would be a different story for virtual ideas.


Darren for http://www.shoppingformen.com.au/

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.