Design patterns are used to solve the problems which occur in a pattern, we all know that, right? Also we know that behavioral design patterns are design patterns that identify common communication patterns between objects. One of such behavioral patterns is visitor pattern, which we are going to learn about in this post.
If you have been in working on a application which manage plenty of products, then you can easily relate with this problem:
So clearly, you want a hierarchy of objects to modify their behavior but without modifying their source code. How to do that? To solve this problem, visitor pattern comes into picture.
Sections in this post: Visitor pattern introduction Design participants/components Sample problem to solve Proposed solution using Visitor pattern Implementation code How to use visitors in application code Sourcecode download
Visitor pattern introduction
According to Wikipedia, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures. It is one way to follow the open/closed principle (one of SOLID design principles).
Above design flexibility allows to add methods to any object hierarchy without modifying the code written for hierarchy. Rather double dispatch mechanism is used to implement this facility. Double dispatch is a special mechanism that dispatches a function call to different concrete functions depending on the runtime types of two objects involved in the call.
Design participants/components
The participants classes in this pattern are:
Visitor – This is an interface or an abstract class used to declare the visit operations for all the types of visitable classes.
ConcreteVisitor – For each type of visitor all the visit methods, declared in abstract visitor, must be implemented. Each Visitor will be responsible for different operations.
Visitable – is an interface which declares the accept operation. This is the entry point which enables an object to be “visited” by the visitor object.
ConcreteVisitable – Those classes implements the Visitable interface or class and defines the accept operation. The visitor object is passed to this object using the accept operation.
Sample problem to solve
An example is always better than long theory. So let’s have one here also for visitor design pattern.
Suppose we have an application which manage routers in different environments. Routers should be capable of sending and receiving char data from other nodes and application should be capable of configuring routers in different environment.
Essentially, design should flexible enough to support the changes in way that routers can be configured for additional environments in future, without much modifications in source code.

We have above 3 types of routers and we need to write code for them. One way to solve this problem, is to define methods like configureForWinodws() and configureForLinux() in Router.java interface and implement them in different products, cause each will have it’s own configuration setting and procedure.
But the problem with above approach is that each time a new environment is introduced, whole router’s hierarchy will have to be compiled again. Not acceptable solution. So what is it which can prevent this situation?
Proposed solution using Visitor pattern
Visitor pattern is good fit for these types of problems where you want to introduce a new operation to hierarchy of objects, without changing its structure or modifying them. In this solution, we will implement double dispatch technique by introducing two methods i.e. accept() and visit() methods. Method accept(), will be defined in router’s hierarchy and and visit methods will be on visitors level.
Whenever a new environment need to be added, a new visitor will be added into visitors hierarchy and that needs to implement visit() method for all the available routers and that’s all.

In above class diagram, we have routers configured for Mac and Linux operating systems. If we need to add the capability for windows also, then I do not need to change any class, just define a new visitor WindowsConfigurator and implement the visit() methods defined in RouterVisitor interface. It will provide the desired functionality without any further modification.
Implementation code
Let’s look at the source code of different files involved into above discussed problem and solution.
Router.java
public interface Router { public void sendData(char[] data); public void acceptData(char[] data); public void accept(RouterVisitor v); }
DLinkRouter.java
public class DLinkRouter implements Router{ @Override public void sendData(char[] data) { } @Override public void acceptData(char[] data) { } @Override public void accept(RouterVisitor v) { v.visit(this); } }
LinkSysRouter.java
public class LinkSysRouter implements Router{ @Override public void sendData(char[] data) { } @Override public void acceptData(char[] data) { } @Override public void accept(RouterVisitor v) { v.visit(this); } }
TPLinkRouter.java
public class TPLinkRouter implements Router{ @Override public void sendData(char[] data) { } @Override public void acceptData(char[] data) { } @Override public void accept(RouterVisitor v) { v.visit(this); } }
RouterVisitor.java
public interface RouterVisitor { public void visit(DLinkRouter router); public void visit(TPLinkRouter router); public void visit(LinkSysRouter router); }
LinuxConfigurator.java
public class LinuxConfigurator implements RouterVisitor{ @Override public void visit(DLinkRouter router) { System.out.println("DLinkRouter Configuration for Linux complete !!"); } @Override public void visit(TPLinkRouter router) { System.out.println("TPLinkRouter Configuration for Linux complete !!"); } @Override public void visit(LinkSysRouter router) { System.out.println("LinkSysRouter Configuration for Linux complete !!"); } }
MacConfigurator.java
public class MacConfigurator implements RouterVisitor{ @Override public void visit(DLinkRouter router) { System.out.println("DLinkRouter Configuration for Mac complete !!"); } @Override public void visit(TPLinkRouter router) { System.out.println("TPLinkRouter Configuration for Mac complete !!"); } @Override public void visit(LinkSysRouter router) { System.out.println("LinkSysRouter Configuration for Mac complete !!"); } }
How to use visitors in application code
To use above design, use the visitors in below given way. I have used the code in form of JUNIT testcases, you can change the code the way you feel correct into your case.
TestVisitorPattern.java
public class TestVisitorPattern extends TestCase { private MacConfigurator macConfigurator; private LinuxConfigurator linuxConfigurator; private DLinkRouter dlink; private TPLinkRouter tplink; private LinkSysRouter linksys; public void setUp() { macConfigurator = new MacConfigurator(); linuxConfigurator = new LinuxConfigurator(); dlink = new DLinkRouter(); tplink = new TPLinkRouter(); linksys = new LinkSysRouter(); } public void testDlink() { dlink.accept(macConfigurator); dlink.accept(linuxConfigurator); } public void testTPLink() { tplink.accept(macConfigurator); tplink.accept(linuxConfigurator); } public void testLinkSys() { linksys.accept(macConfigurator); linksys.accept(linuxConfigurator); } } Output: DLinkRouter Configuration for Mac complete !! DLinkRouter Configuration for Linux complete !! LinkSysRouter Configuration for Mac complete !! LinkSysRouter Configuration for Linux complete !! TPLinkRouter Configuration for Mac complete !! TPLinkRouter Configuration for Linux complete !!
Sourcecode download
To download the sourcecode of above application, follow given link.
Happy Learning !!