dagblog.
← Archive

Visitor in practice


One of my favorite design patterns is Visitor, though I rarely see it used. As with most design patterns, except perhaps the utterly overexposed Singleton, it seems that in theory we know all the patterns and in practice can use only one or two. This article is a practical reminder of what I use this pattern for.

I use Visitor when I need to work with a branching object structure. The usual operations are to traverse the structure and find all objects meeting some criterion, or to traverse it and change something along the way.

Take Tree, Branch, and Leaf objects arranged in an aggregate. A Tree has N Branch objects, each of which has N Leaf objects.

The key is to think about what the code for any operation on this structure will look like. Every case has the same code for traversing the structure, followed by a small amount of code that performs the operation itself.

That’s exactly the kind of problem the Visitor pattern fits. Each object in the aggregate implements the shared code itself, meaning depth-first traversal of the hierarchy. The operation on each object is delegated to the Visitor, which is passed as a method argument.

The great thing about the pattern is that you can add operations on the structure without changing the original objects. The operations can be cleanly encapsulated in objects too. That gets rid of the spaghetti code, the procedural code where we’d mix traversal and the operation on the structure. We get a clean separation of responsibilities. That makes testing easier, which is almost always a sign of good object-oriented design.

Let’s say we want an operation that colors every second leaf on the tree yellow.

public class Marker implements Visitor{
private int leafCounter = 1;
@Override
public void visitLeaf(final Leaf leaf) {
if(leafCounter % 2 == 0) {
leaf.setColor("yellow");
}
leafCounter++;
}
}
The test is then very simple (I’m using Mockito).
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import org.junit.Test;
public class MarkerTest {
@Test
public void testVisitLeaf() {
Leaf leaf = mock(Leaf.class);
Marker marker = new Marker();
marker.visitLeaf(leaf);
verify(leaf, never()).setColor(anyString());
marker.visitLeaf(leaf);
verify(leaf).setColor(eq("yellow"));
}
}
Here’s how to use the concrete visitor:
Tree tree = new Tree();
Marker marker = new Marker();
tree.accept(marker);
The source files are available on GitHub.

Medium version

Related articles

Related CZ Podcast episodes