Visitor Design Pattern Example

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:

“You need to add a new method to a hierarchy of classes, but the act of adding it might be painful or damaging to the design.”

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.

Existing routers in application
Existing routers in application

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.

Solution using visitor pattern
Solution using visitor pattern

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 !!

Comments

Subscribe
Notify of
guest
18 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.

Our Blogs

REST API Tutorial

Dark Mode

Dark Mode