The visitor pattern allows you to easily perform a given operation (function, algorithm, etc...) on each element of a complex structure. The benefit is that you can easily add other operations to perform and you can easily change the structure of the elements. The principle is that the classes that are used to perform the operations and the classes that scrolls the structures are different. It also means that if you know that you will always have only one operation to perform on the structure, this pattern is useless.

Let's take the simple data class:

Element

We want to perform an operation on it. Instead of implement it inside of the class, we will use a visitor class. A visitor class is a class that performs an action on an object. It will perform an action on a whole structure by being called for each element. However, for now, we only have one object. The visitor will be called by the visit method by the data object and the object will be called by the accept method by the client:

Client

<<interface>>
Visitor

+visit(Element)

Element

+accept(Visitor)

ConcreteVisitor

+visit(Element)

ConcreteElement

+accept(Visitor)

Then you can define a structure of data object and each object will call the accept() method on its sub-elements. You may think that the main drawback of this pattern is that even if the visitor can process all the elements, it does not process it as a whole, i.e. it can't connect the different elements together so the pattern is limited. Not at all. The visitor can keep information about the elements it has already visited (for example to log lines with appropriate indentation). If the visitor needs information from all the element (for example to compute a percentage based on the sum), then it can visit all the elements, store information, and actually process all the information after the last visit using another method. In other word, you can add states to your visitor.

This process is essentially equivalent to getting the collection's iterator, and using a while(iterator.hasNext()) loop to invoke visitor.visit(iterator.next()). The key difference is that the collection can decide exactly how to step through the elements. If you're familiar with iterators, you may be thinking that the iterator can decide how to step through, too, and the iterator is usually defined by the collection, so what's the difference? The difference is that the iterator is still bound to a while loop, visiting each element in succession, one at a time. With the visitor pattern, the collection could conceivably create a separate thread for each element and have the visitor visiting them concurrently. That's just one example of ways that the collection may decide to vary the method of visitation in a manner that can't be mimicked by an iterator. The point is, it's encapsulated, and the collection can implement the pattern in what ever way it feels is best. More importantly, it can change the implementation at any time, without affecting client code, because the implementation is encapsulated in the foreach method.

An example implementation of Visitor Pattern: String

To illustrate the visitor pattern, let's imagine we're reinventing Java's String class (it'll be a pretty ridiculous reinvention, but it'll be good for this exercise). We're not going to implement very much of the class, but let's assume that we're storing a set of chars that make up the string, and we have a method called getCharAt which takes an int as its only argument, and returns the character at that position in the string, as a char. We also have a method called length which takes no arguments, and returns an int which gives the number of characters in the string. Let's also assume that we want to provide an implementation of the visitor pattern for this class which will take an instance that implements the CharacterVisitor interface (which we'll define, below), and calls its visit method for each character in the string. First we need to define what this CharacterVisitor interface looks like:

publicinterfaceCharacterVisitor{publicvoidvisit(charaChar);}

Easy enough. Now let's get down to our class, which we'll call MyString, and it looks something like this:

publicclassMyString{// ... other methods, fields// Our main implementation of the visitor patternpublicvoidforeach(CharacterVisitoraVisitor){intlength=this.length();// Loop over all the characters in the stringfor(inti=0;i<length;i++){// Get the current character, and let the visitor visit it.aVisitor.visit(this.getCharAt(i));}}// ... other methods, fields}// end class MyString

So that was pretty painless. So what can we do with this? Well let's make a class called MyStringPrinter, which prints an instance of MyString to the standard output.

publicclassMyStringPrinterimplementsCharacterVisitor{// We have to implement this method because we're implementing the CharacterVisitor// interfacepublicvoidvisit(charaChar){// All we're going to do is print the current character to the standard outputSystem.out.print(aChar);}// This is the method you call when you want to print a stringpublicvoidprint(MyStringaStr){// we'll let the string determine how to get each character, and// we already defined what to do with each character in our// visit method.aStr.foreach(this);}}// end class MyStringPrinter

That was simple too. Of course, it could've been a lot simpler, right? We didn't need the foreach method in MyString, and we didn't need MyStringPrinter to implement the visitor, we could have just used the MyString classes getCharAt and length methods to set up our own for loop ourselves and printed each char inside the loop. Well sure you could, but what if MyString isn't MyString but instead is MyBoxOfRocks.

Another example implementation of Visitor Pattern: Rock

In a box of rocks, is there a set order that the rocks are in? Unlikely. Of course MyBoxOfRocks has to store the rocks somehow. Maybe it stores them in an array, and there is actually a set order of the rocks, even if it is artificially introduced for the sake of storage. On the other hand, maybe it doesn't. The point is once again, that's an implementation detail that you as the client of MyBoxOfRocks shouldn't have to worry about, and should never rely on.

Presumably, MyBoxOfRocks wants to provide someway for clients to get at the rocks inside it. It could, once again, introduce an artificial order to the rocks; assign each rock an index and provide a method like public Rock getRock(int aRockNumber). Or maybe it wants to put names on all the rocks and let you access it like public Rock getRock(String aRockName). But maybe it's really just a box of rocks, and there's no names, no numbers, no way of identifying which rock you want, all you know is you want the rocks. Alright, let's try it with the visitor pattern. First out visitor interface (assume Rock is already defined somewhere, we don't care what it is or what it does):

publicinterfaceRockVisitor{publicvoidvisit(RockaRock);}

Easy. Now out MyBoxOfRocks

publicclassMyBoxOfRocks{privateRock[]fRocks;//... some kind of instantiation codepublicvoidforeach(RockVisitoraVisitor){intlength=fRocks.length;for(inti=0;i<length;i++){aVisitor.visit(fRocks[i]);}}}// End class MyBoxOfRocks

Huh, what do you know, it does store them in an array. But what do we care now? We already wrote the visitor interface, and all we have to do now is implement it in some class which defines the actions to take for each rock, which we would have to do inside a for loop anyway. Besides, the array is private, our visitor doesn't have any access to that.

And what if the implementor of MyBoxOfRocks did a little homework and found out that comparing a number to zero is infinitesimally faster than comparing it to a non zero. Infinitesimal, sure, but maybe when you're iterating over 10 million rocks, it makes a difference (maybe). So he decides to change the implementation:

Now he's iterating backwards through the array and saving a (very) little time. He's changed the implementation because he found a better way. You didn't have to worry about finding the best way, and you didn't have to change your code because the implementation is encapsulated. And that's not the half of it. Maybe a new coder takes control of the project, and maybe this coder hates arrays and decides to totally change it:

publicclassMyBoxOfRocks{// This coder really likes Linked ListsprivateclassRockNode{RockiRock;RockNodeiNext;RockNode(RockaRock,RockNodeaNext){this.iRock=aRock;this.iNext=aNext;}}// end inner class RockNodeprivateRockNodefFirstRock;// ... some instantiation code goes in here// Our new implementationpublicvoidforeach(RockVisitoraVisitor){RockNodecurrent=this.fFirstRock;// a null value indicates the list is endedwhile(current!=null){// have the visitor visit the current rockaVisitor.visit(current.iRock);// step to the next rockcurrent=current.iNext;}}}

Now maybe in this instance, linked lists were a poor idea, not as fast as a nice lean array and a for loop. On the other hand, you don't know what else this class is supposed to do. Maybe providing access to the rocks is only a small part of what it does, and linked lists fit in better with the rest of the requirements. In case I haven't said it enough yet, the point is that you as the client of MyBoxOfRocks don't have to worry about changes to the implementation, the visitor pattern protects you from it.

I have one more trick up my sleeve. Maybe the implementor of MyBoxOfRocks notices that a lot of visitors are taking a really long time to visit each rock, and it's taking far too long for the foreach method to return because it has to wait for all visitors to finish. He decides it can't wait that long, and he also decides that some of these operations can probably be going on all at once. So he decides to do something about it, namely, this:

// Back to our backward-array modelpublicvoidforeach(RockVisitoraVisitor){Threadt;// This should speed up the returnintlength=fRocks.length;for(inti=length-1;i>=0;i--){finalRockcurr=fRocks[i];t=newThread(){publicvoidrun(){aVisitor.visit(curr);}};// End anonymous Thread classt.start();// Run the thread we just created.current=current.iNext;}}

If you're familiar with threads, you'll understand what's going on here. If you're not, I'll quickly summarize: a Thread is basically something that can run "simultaneously" with other threads on the same machine. They don't actually run simultaneously of course, unless maybe you have a multi-processor machine, but as far as Java is concerned, they do. So for instance, when we created this new Thread called t, and defined what happens when the Thread is run (with the run method, naturally), we can then start the Thread a-running and it will start running, splitting cycles on the processor with other Threads, right away, it doesn't have to wait for the current method to return. Likewise, we can start it running and then continue on our own way immediately, without waiting for it to return. So with the above implementation, the only time we need to spend in this method is the time it takes to instantiate all the threads, start them running, and loop over the array; we don't have to wait for the visitor to actually visit each Rock before we can loop, we just loop right away, and the visitor does its thing on whatever CPU cycles it can swipe. The whole visiting process might take just as long (maybe even longer if it looses some cycles because of the multiple threads), but the thread from which foreach was invoked doesn't have to wait for it to finish, it can return from the method and be on it's way much faster.

If you're confused about the use of the final Rock called curr in the above code, it's just a bit of a technicality for using anonymous classes: they can't access non final local variables. Even though fRocks doesn't fit into this category (it's not local, it's an instance variable), it i does. If you tried to remove this line and simply put fRocks[i] in the run method, it wouldn't compile.

So what happens if you're the visitor, and you decide that you need to visit each rock one at a time? There's a number of reasons this might happen such as if your visit method changes your instance variables, or maybe it depends on the results of previous calls to visit. Well the implementation inside the foreach method is encapsulated from you, you don't know if it's using separate threads or not. Sure you could figure it out with some fancy debugging, or some clever printing to std out, but wouldn't it be nice if you didn't have to? And if you could be sure that if they change it in the next version, your code will still work properly? Well fortunately, Java provides the synchronize mechanism, which is basically an elaborate device for locking up blocks of code so that only one Thread can access them at a time. This won't conflict with the interests of the multi-threaded implementation, either, because the locked out thread still won't block the thread that created them, they'll just sit and wait patiently, only blocking code on itself. That's all well beyond the scope of this section, however, but be aware that it's available and probably worth looking into if you're going to be using synchronicity-sensitive visitors.

Examples

To do:
Find an example.

Cost

This pattern is flexible enough not to block you because of it. At worst, you will need to spend time thinking about how to solve problems but this pattern will never block you.

Creation

This pattern is expensive to create if your code already exists.

Maintenance

It is easy to adapt the code with this pattern, even if there are new links between the item visits.

Removal

This pattern can be removed using refactoring operations from your IDE.

Advises

Use the visitor and visit term to indicate the use of the pattern to the other developers.

If you have and will always have only one visitor, you'd rather implement the composite pattern.

1 classWheelimplementsCarElement{ 2 privateStringname; 3 4 publicWheel(Stringname){ 5 this.name=name; 6 } 7 8 publicStringgetName(){ 9 returnthis.name;10 }11 12 publicvoidaccept(CarElementVisitorvisitor){13 /*14 * accept(CarElementVisitor) in Wheel implements15 * accept(CarElementVisitor) in CarElement, so the call16 * to accept is bound at run time. This can be considered17 * the first dispatch. However, the decision to call18 * visit(Wheel) (as opposed to visit(Engine) etc.) can be19 * made during compile time since 'this' is known at compile20 * time to be a Wheel. Moreover, each implementation of21 * CarElementVisitor implements the visit(Wheel), which is22 * another decision that is made at run time. This can be23 * considered the second dispatch.24 */25 visitor.visit(this);26 }27 }