Visitor Pattern Design Patterns in Java

This article explains about the visitor pattern of the GoF Design Behavior patterns. In the visitor design pattern, the visitor class is used to alter the algorithm that is executing as part of the element class. This is an easy methodology to control the algorithm executing for elements by using the visitor class, as the executing algorithm varies with the variance in the visitor class.

The Visitor class is considered as a type of Behavior pattern that presents an implementation of the exchange of place with the exchange of control mechanism. As the object of the element, the class must provide a place to the object of the visitor class in order for it to control the element class. The visitor class is the controller of all variance in the operations of the element class.

Visitor Pattern

According to the Gang of Four:

Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

UML Class Diagram
visitor pattern

Visitor Class

  • The visitor class performs the mechanism of controlling any sort of variance in the element class. The object of the visitor class resides in the element class for control.

Element Class

  • The element class is the main class performing critical operations whose variations are controlled by the visitor class.
  • The operation that is performed on the element is represented through visitor behavioural pattern. A new operation can be defined by the Visitor class without any alteration to the normal classes belonging to the element being operated on. Many operations that are not related to each other are performed on a structure that is composed of heterogeneous node objects which can pollute the classes of the node objects.
  • To avoid pollution, querying is performed on nodes to determine the correct type and point the operation to it. This is quite inefficient as it cost a lot of time and resources for querying every node and waiting for a response. The Visitor Behavioral Pattern provides a solution with this by abstracting functionalities on element objects aggregated together in a hierarchical structure.

Spring 5 Design Pattern Book

You could purchase my Spring 5 book that is with title name “Spring 5 Design Pattern“. This book is available on the Amazon and Packt publisher website. Learn various design patterns and best practices in Spring 5 and use them to solve common design problems. You could use an author discount to purchase this book by using code- “AUTHDIS40“.
Spring-5-Design-Pattern

The Element classes are created in such a way that includes only the necessary functionalities and the Visitor subclasses are created that provide the additional functionality for the Element class. A double dispatch mechanism is implemented by the Visitor Class in which, the request’s name and the Visitor type and Element type both act as receivers these things determine the operation that will be performed.

Visitor Design Pattern Implementation

This can be implemented by creating a Visitor hierarchy through the pure virtual class of the visitor. A method visit() is declared in the base class of the Visitor and it is overloaded in the child/derived classes by using the specific methodology of querying and casting. The visitor() method receives the pointer to the derived class for the Element class. The base class of the Element class has an accept() method which accepts the pointer to the base class of the Visitor class. The accept() method can be implemented on the Element’s concrete derived class by calling the visit() method on the Visitor’s derived instance.

The accept() method is responsible for the selection of the Element class to be controlled and the visit() method allocated the control to the correct Visitor instance. This allows related and unrelated operations to be performed on an object that is aggregated into a single hierarchical structure.

Visitor Pattern Sample Example

In this sample real-world example, we demonstrate the Visitor pattern in which two objects traverse a list of Employees and perform the same operation on each Employee. There are two visitor objects define different operations. These operations are one adjusts vacation days and the other income.

VisitorPatternDemo, our demo class, will use Employee and Visitor classes to demonstrate the use of visitor pattern.

Step 1: Define an interface to represent element.
Element.java

/**
 * 
 */
package com.doj.patterns.behavior.visitor;

/**
 * @author Dinesh.Rajput
 *
 */
public interface Element {
	
	void accept(IVisitor visitor);
}

Step 2: Create concrete classes extending the above class.
Employee.java

/**
 * 
 */
package com.doj.patterns.behavior.visitor;

/**
 * @author Dinesh.Rajput
 *
 */
public class Employee implements Element {
	
	private String _name;
    private double _income;
    private int _vacationDays;
    
    
	public Employee(String _name, double _income, int _vacationDays) {
		super();
		this._name = _name;
		this._income = _income;
		this._vacationDays = _vacationDays;
	}

	@Override
	public void accept(IVisitor visitor) {
		visitor.visit(this);
	}

	public String get_name() {
		return _name;
	}

	public void set_name(String _name) {
		this._name = _name;
	}

	public double get_income() {
		return _income;
	}

	public void set_income(double _income) {
		this._income = _income;
	}

	public int get_vacationDays() {
		return _vacationDays;
	}

	public void set_vacationDays(int _vacationDays) {
		this._vacationDays = _vacationDays;
	}
	
}

Director.java

/**
 * 
 */
package com.doj.patterns.behavior.visitor;

/**
 * @author Dinesh.Rajput
 *
 */
public class Director extends Employee {

	public Director() {
		super("Anamika", 45000.0, 20);
	}

}

President.java

/**
 * 
 */
package com.doj.patterns.behavior.visitor;

/**
 * @author Dinesh.Rajput
 *
 */
public class President extends Employee {

	public President() {
		super("Arnav", 65000.0, 25);
	}

}

Clerk.java

/**
 * 
 */
package com.doj.patterns.behavior.visitor;

/**
 * @author Dinesh.Rajput
 *
 */
public class Clerk extends Employee {

	public Clerk() {
		super("Dinesh", 35000.0, 18);
	}

}

Employees.java

/**
 * 
 */
package com.doj.patterns.behavior.visitor;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Dinesh.Rajput
 *
 */
public class Employees {
	
	// Setup employee collection
	List empList = new ArrayList<>();
	
	public void add(Employee employee){
		empList.add(employee);
    }

    public void remove(Employee employee){
    	empList.remove(employee);
    }

    public void accept(IVisitor visitor){
    	for(Employee employee : empList)	{
    		employee.accept(visitor);
    	}
    	System.out.println();
    }
}

Step 3: Define an interface to represent visitor.
IVisitor.java

/**
 * 
 */
package com.doj.patterns.behavior.visitor;

/**
 * @author Dinesh.Rajput
 *
 */
public interface IVisitor {
	
	void visit(Element element);
}

Step 4: Create a concrete visitor implementing the above class.
IncomeVisitor.java

/**
 * 
 */
package com.doj.patterns.behavior.visitor;

/**
 * @author Dinesh.Rajput
 *
 */
public class IncomeVisitor implements IVisitor {

	@Override
	public void visit(Element element) {
		Employee employee = (Employee) element;
		// Provide 10% pay raise
		employee.set_income(employee.get_income()*1.10);
		System.out.println(employee.getClass().getSimpleName()+" "+employee.get_name() +"'s new income: "+employee.get_income());
	}
}

VacationVisitor.java

/**
 * 
 */
package com.doj.patterns.behavior.visitor;

/**
 * @author Dinesh.Rajput
 *
 */
public class VacationVisitor implements IVisitor {

	@Override
	public void visit(Element element) {
		Employee employee = (Employee) element;
		// Provide 3 extra vacation days
		employee.set_vacationDays(employee.get_vacationDays()+3);
		System.out.println(employee.getClass().getSimpleName()+" "+employee.get_name() +"'s vacation days: "+employee.get_vacationDays());
	}
}

Step 5: VisitorPatternDemo, our demo class, will use Employee and Visitor classes to demonstrate the use of visitor pattern.

VisitorPatternDemo.java

/**
 * 
 */
package com.doj.patterns.behavior.visitor;

/**
 * @author Dinesh.Rajput
 *
 */
public class VisitorPatternDemo {
	
	public static void main(String[] args) {
		
		// Setup employee collection
		Employees employees = new Employees();
		employees.add(new Clerk());
		employees.add(new Director());
		employees.add(new President());
		
		 // Employees are 'visited'
		employees.accept(new IncomeVisitor());
		employees.accept(new VacationVisitor());
	}
}

Step 6: Let’s run this demo class and verify the output.

Clerk Dinesh's new income: 38500.0
Director Anamika's new income: 49500.00000000001
President Arnav's new income: 71500.0

Clerk Dinesh's vacation days: 21
Director Anamika's vacation days: 23
President Arnav's vacation days: 28

Previous
Next

2 Comments

  1. Leonel Aquino May 29, 2019
  2. Dinesh Rajput May 29, 2019