When I find a concept difficult to understand I try to strip it to bare essentials. This happened to me recently with the visitor pattern so here is my take on it. Of course I will be grateful for any corrections. Here goes.
Let’s say we have three classes derived from a common parent, called A
abstract class A
{
public String name;
abstract void accept(Visitor v);
}
class B that has two objects as components:
class B extends A
{
public A child1;
public A child2;
public B(String name)
{
this.name = name;
}
[@Override](http://twitter.com/Override)
void accept(Visitor v)
{
v.visitB(this);
}
}
class C that has one component:
class C extends A
{
public A child;
public C(String name)
{
this.name = name;
}
[@Override](http://twitter.com/Override)
void accept(Visitor v)
{
v.visitC(this);
}
}
and class D that has no components
class D extends A
{
public D(String name)
{
this.name = name;
}
[@Override](http://twitter.com/Override)
void accept(Visitor v)
{
v.visitD(this);
}
}
All three classes expose a property, name that lets us distinguish their instances and a method named accept that allows visitors to visit them. The classes don’t care and don’t need to know what their visitors do. Visitor is an interface:
interface Visitor
{
public void visitB(B b);
public void visitC(C c);
public void visitD(D d);
}
There is a method for each class it visits. Let’s try this out with a visitor implementation that just prints out the name of objects it visited:
class PrintVisitor implements Visitor
{
public void visitB(B b)
{
b.child1.accept(this);
System.out.println(b.name + " visited.");
b.child2.accept(this);
}
public void visitC(C c)
{
System.out.println(c.name + " visited.");
c.child.accept(this);
}
public void visitD(D d)
{
System.out.println(d.name + " visited.");
}
}
The visitor is recursive: it visits a tree node and then it visits its children. Now let’s make a tree made up from the classes B, C and D:
/\*
F
/ \
B G
/ \ \
A D H
/ \ \
C E I
\*/
There are nine objects and seven relations. First, create the objects:
B f = new B("F");
B b = new B("B");
B d = new B("D");
C g = new C("G");
C h = new C("H");
D a = new D("A");
D c = new D("C");
D e = new D("E");
D i = new D("I");
Next, the relations:
f.child1 = b;
f.child2 = g;
b.child1 = a;
b.child2 = d;
d.child1 = c;
d.child2 = e;
g.child = h;
h.child = i;
And finally start visiting our tree by visiting its root node:
PrintVisitor v = new PrintVisitor();
f.accept(v);
The output is:
A visited.
B visited.
C visited.
D visited.
E visited.
F visited.
G visited.
H visited.
I visited.
If you look at this article, the above code performs tree traversal, and what is called in-order traversal at that (). Let’s change our visitor class to do a pre-order traversal — the visitor first displays the node name and then visits its children:
class PrintVisitor implements Visitor
{
public void visitB(B b)
{
System.out.println(b.name + " visited.");
b.child1.accept(this);
b.child2.accept(this);
}
public void visitC(C c)
{
System.out.println(c.name + " visited.");
c.child.accept(this);
}
public void visitD(D d)
{
System.out.println(d.name + " visited.");
}
}
Now the output is:
F visited.
B visited.
A visited.
D visited.
C visited.
E visited.
G visited.
H visited.
I visited.
In post-order traversal the visitor first visits node children and only then displays its name:
class PrintVisitor implements Visitor
{
public void visitB(B b)
{
b.child1.accept(this);
b.child2.accept(this);
System.out.println(b.name + " visited.");
}
public void visitC(C c)
{
c.child.accept(this);
System.out.println(c.name + " visited.");
}
public void visitD(D d)
{
System.out.println(d.name + " visited.");
}
}
Here is the output:
A visited.
C visited.
E visited.
D visited.
B visited.
I visited.
H visited.
G visited.
F visited.
Besides the Wikipedia article I linked at the beginning, there is a nice description of the visitor pattern here. In short:
- The visited objects don’t need to know what their visitors do, they just need to accept them.
- There needs to be a protocol that lets visited objects and visitors communicate, in our case the Visitor interface.
- A visitor uses separate methods (ie visitB, visitC and visitD for visiting each class)
(You can find the code on Github.)
Top comments (0)