Visitor Design Pattern in Java
Last Updated :
03 May, 2024
The Visitor Design Pattern is a behavioral design pattern that allows you to separate algorithms or operations from the objects on which they operate. It enables you to add new operations to objects without modifying their structure.
.webp)
Important Topics for Visitor Design Pattern in Java
What is the Visitor Design Pattern?
The Visitor Design Pattern is a behavioral design pattern that enables the separation of algorithms or operations from the objects they operate on. It allows you to define new operations on a collection of objects without modifying their classes directly. In essence, the Visitor pattern facilitates adding new behaviors or operations to an object structure by encapsulating them in separate visitor objects, thereby promoting extensibility and flexibility in the design.
Real-Life Example of the Visitor Design Pattern
Imagine you own a zoo with different types of animals: lions, monkeys, and elephants. Now, you want to perform various tasks on these animals, such as feeding, cleaning, and monitoring their health.
Instead of modifying each animal's class to accommodate these tasks, you can implement the Visitor pattern:
- The zookeepers represent the visitors.
- The animals represent the elements.
- Each type of animal (lion, monkey, elephant) has specific tasks associated with it.
Here's how it works:
- Each animal has an accept method that allows a zookeeper to visit it.
- When a zookeeper visits an animal, the animal invokes the appropriate method on the zookeeper, depending on its type.
- For example, if a zookeeper wants to feed a lion, the lion would invoke the feed method on the zookeeper.
- Similarly, if a zookeeper wants to clean an elephant enclosure, the elephant would invoke the clean method on the zookeeper.
By using the Visitor pattern in this scenario, you can add new types of tasks or visitors to the zoo without changing the existing animal classes. This makes it easier to manage and extend the zoo's functionality over time.
Key Components in the Visitor Design Pattern
1. Visitor Interface
- The Visitor interface sets the visit methods, and every method corresponds to some kind of element in the object structure.
- Such techniques take various methods to call specific types of elements as the arguments.
- The interface definition is what the Visitor Method uses to separate operations (caused by concrete visitors) from the elements (defined by concrete elements), improving the agility and extensibility of the system.
2. Element Interface
- The Element interface has a declared accept method with a parameter of a visitor object.
- It is this technique that helps the visitor to execute the method on the element.
- Consequently, each concrete element class has a defined method to call the suitable visit procedure of the visitor. It enables the Visitor Method to dynamically run the visit methods considered with the type of element found.
3. Concrete Visitors
- Concrete visitors are the implementations of visitor interfaces in concrete form. Every concretitude suggests one single operation to be performed on the subject matter.
- Hence, after the visit technique has been implemented, visitors are the ones who will then define the behavior for each element type.
- Concrete Visitors like algorithms or behavior encapsulating the elements, putting off crosscutting concerns and maintainability.
4. Concrete Element
- Concrete elements implement concrete classes of the interface element. Concrete classes correspond to each concrete element class in the element structure.
- Concrete Elements implements an accept method that can invoke the similar corresponding visit method of the visitor.
- This provides the visitor a chance to access the internal state and to work with the element. Concrete aspects of the model cover the data and behavior characteristics unique to each of the elements involved.
UML Class Diagram of the Visitor Design Pattern
.webp)
Example of the Visitor Design Pattern
Below is the problem statement to understand visitor design pattern:
Assume a situation whereby you have a set of shapes like circles, squares, and triangles. You want to find the area of each given figure. One option is to add a method that calculates the area of each shape class. Yet, it breaks the open-closed principle, as modifying existing classes is mandatory whenever a new operation emerges.
There are the following steps for implementing Visitor Design Method:
Step 1: Define the Visitor interface:
Java
public interface ShapeVisitor {
void visit(Circle circle);
void visit(Square square);
void visit(Triangle triangle);
}
Step 2: Define the Element interface:
Java
public interface Shape {
void accept(ShapeVisitor visitor);
}
Step 3: Implement Concrete Elements:
Java
public class Circle implements Shape {
// Circle specific properties and methods
@Override
public void accept(ShapeVisitor visitor) {
visitor.visit(this);
}
}
class Square implements Shape {
@Override
public void accept(ShapeVisitor visitor) {
visitor.visit(this);
}
}
class Triangle implements Shape {
@Override
public void accept(ShapeVisitor visitor) {
visitor.visit(this);
}
}
Step 4: Implement Concrete Visitors:
Java
public class AreaCalculator implements ShapeVisitor {
double totalArea = 0;
@Override
public void visit(Circle circle) {
// Calculate area of circle and update totalArea
totalArea += Math.PI * Math.pow(radiusOfCircle, 2);
}
@Override
public void visit(Square square) {
// Calculate area of square and update totalArea
totalArea += Math.pow(sideOfSquare, 2);
}
@Override
public void visit(Triangle triangle) {
// Calculate area of triangle and update totalArea
totalArea += (baseOfTriangle * heightOfTriangle) / 2;
}
public double getTotalArea() {
return totalArea;
}
}
Complete Code of Visitor Design Pattern
Below is the overall code of the above example:
Java
import java.util.ArrayList;
import java.util.List;
// Visitor interface
interface ShapeVisitor {
void visit(Circle circle);
void visit(Square square);
void visit(Triangle triangle);
}
// Element interface
interface Shape {
void accept(ShapeVisitor visitor);
}
// Concrete Elements
class Circle implements Shape {
@Override
public void accept(ShapeVisitor visitor) {
visitor.visit(this);
}
}
class Square implements Shape {
@Override
public void accept(ShapeVisitor visitor) {
visitor.visit(this);
}
}
class Triangle implements Shape {
@Override
public void accept(ShapeVisitor visitor) {
visitor.visit(this);
}
}
// Concrete Visitors
class AreaCalculator implements ShapeVisitor {
private double totalArea = 0;
double radiusOfCircle = 5;
double sideOfSquare = 4;
double baseOfTriangle = 3;
double heightOfTriangle = 6;
@Override
public void visit(Circle circle) {
// Calculate area of circle and update totalArea
totalArea += Math.PI * Math.pow(radiusOfCircle, 2);
}
@Override
public void visit(Square square) {
// Calculate area of square and update totalArea
totalArea += Math.pow(sideOfSquare, 2);
}
@Override
public void visit(Triangle triangle) {
// Calculate area of triangle and update totalArea
totalArea += (baseOfTriangle * heightOfTriangle) / 2;
}
public double getTotalArea() {
return totalArea;
}
}
// Main class
public class Main {
public static void main(String[] args) {
List<Shape> shapes = new ArrayList<>();
shapes.add(new Circle());
shapes.add(new Square());
shapes.add(new Triangle());
AreaCalculator areaCalculator = new AreaCalculator();
for (Shape shape : shapes) {
shape.accept(areaCalculator);
}
System.out.println("Total area: " + areaCalculator.getTotalArea());
}
}
Output
Use Cases of the Visitor Design Pattern
Below are the use cases of visitor design pattern:
- Document Processing:
- In document processing applications you regularly operate with complicated structures of objects representing different types of elements like paragraphs, headings, lists, images, etc.
- The Visitor Method can be applied to these objects to perform various operations without their classes.
- For instance, you could determine an interface for visitors consisting of techniques for creating HTML or PDF representations of document elements.
- User format whatsoever is sure to encompass a particular action for each element type thus cleanly separating the concerns and keeping the processes modular in the documents processing systems.
- Compiler Design:
- In the Visitor Method of compiler design, traversing through the abstract syntax trees (ASTs) and performing several compiler tasks like type checking, optimization, and code generation are done.
- Every node in the AST demonstrates an expression, statement, or function, and the Visitor Method helps you act on these nodes by defining different operations without modifying the classes.
- For example, you could define a visitor interface with methods for performing type-checking on expressions and statements, and concrete implementations sourcing specific type-checking logic for each node type.
- GUI Component Frameworks:
- In graphical user interface (GUI) component frameworks, the Visitor Method can perform various operations on the components of the GUI hierarchy like rendering, event handling, or layout.
- Every element of the GUI hierarchy signifies a different type of visual component (for instance, the buttons, panels, and text fields), so the Visitor Method enables one to specify different operations on these components without needing to change their classes. For example, there could be interfaces for the visitor that can be used to render components and concrete visitors which will include concrete rendering logic for each component type.
Advantages of the Visitor Design Pattern
Below are the advantages of visitor design pattern:
- Separation of Concerns:
- Visitor Pattern that creates cleanness of responsibilities by structuring the algorithm or operation independent of the object that this operation acts on.
- This separation lets you decouple the pure logic of an operation in a class and gives you concrete visitors as concrete implementations.
- This makes the code so much easier to understand and maintain.
- Open/Closed Principle:
- By disconnecting the algorithms from the elements inside the object structure, the Visitor Method conforms to the open/closed principle.
- According to the idea of the OCP, classes should be able to be extended however they should not be able to be modified.
- With the Visitor Method, it is possible to insert new operations or algorithms into an existing object structure without having to modify its classes, and this makes it possible to keep the existing code intact and functional.
- Extensibility:
- The visitor Method allows applying iterators and adding new operations to the current object, making it more flexible.
- Contrary to the legacy system, our new abstract visitor implementation can seamlessly add a new concrete visitor just to do some extra operation on the elements without any intrusion into its current codebase.
- Such implementation makes it easy to modify and advance the code according to the needs and ensures that the code can be applied again in many conditions.
- Modularity:
- The Visitor Pattern encourages modular design in that it isolates and keeps the related behavior(s) in a separate visitor implementation.
- Visitors layer every granary visitor on a specific process or procedure, that is simple to grasp, test, and maintain.
- Such modularity brings in standard code organization and scalability, especially in large projects that are difficult to maintain.
Disadvantage of the Visitor Design Pattern
Below are the disadvantages of visitor design pattern:
- Increased Complexity:
- Taking a visitor method approach requires us to determine multiple interfaces and classes, including visitor interfaces, concrete visitor implementations, and element interfaces.
- Moreover, this extra structure might complicate the codebase, thereby making it difficult to understand and maintain even the coders who are unaware of this pattern.
- Violation of Encapsulation:
- In certain cases, the Visitor Pattern can be the source of encapsulation violation. As a visitor usually contains an internal state of elements that visitors need to operate on, these details should be private and, therefore, should not be exposed.
- This violation of encapsulation might lead to a decrease in object structure integrity and make code more sensitive to changes.
- Runtime Overhead:
- Visitor Pattern’s dynamic dispatch mechanics combined with the overheads introduced at runtime, especially in languages with languages that do not optimize method dispatch efficiently.
- Calling the accept method for each time introduces additional time which is being used for relaying the visit method to the visitor which is an object and the element which is an object as well.
- The running cost of some of these tools might be insignificant in the majority of general cases, but in the cases of mission-critical ones, it can be highly consuming.
Similar Reads
State Design Pattern in Java
The State design pattern in Java is a behavioral software design pattern that allows an object to alter its behavior when its internal state changes. It achieves this by encapsulating the object's behavior within different state objects, and the object itself dynamically switches between these state
10 min read
Visitor design pattern
An object-oriented programming method called the Visitor design pattern makes it possible to add new operations to preexisting classes without changing them. It improves the modularity and maintainability of code, which makes it perfect for operations on a variety of object structures. Its advantage
7 min read
Strategy Design Pattern in Java
The Strategy Design Pattern in Java defines a family of algorithms, encapsulates each one, and makes them interchangeable, allowing clients to switch algorithms dynamically without altering the code structure. Important Topics for Strategy Design Pattern in Java What is the Strategy Design Pattern i
13 min read
Prototype Design Pattern in Java
The Prototype Design Pattern in Java is a creational pattern that enables the creation of new objects by copying an existing object. Prototype allows us to hide the complexity of making new instances from the client. The concept is to copy an existing object rather than create a new instance from sc
9 min read
Visitor Method Design Patterns in C++
A visitor design patterns or visitor method is basically defined as a behavioral design pattern that allows us to define a new operation without changing the classes of the elements on which it operates. It is particularly useful when we have a set of related classes, and we want to perform differen
9 min read
Java Design Patterns Tutorial
Design patterns in Java refer to structured approaches involving objects and classes that aim to solve recurring design issues within specific contexts. These patterns offer reusable, general solutions to common problems encountered in software development, representing established best practices. B
8 min read
Strategy Method Design Pattern in Java
Strategy method or Strategy Design Pattern is a behavioral design pattern in Java that defines a family of algorithms, encapsulates each algorithm, and makes them interchangeable. It lets the client algorithm vary independently from the objects that use it. This pattern is useful when you have a fam
11 min read
Visitor Pattern | JavaScript Design Patterns
The visitor pattern is a behavioral design pattern that allows you to add new behaviors or operations to a set of objects without modifying their structure. It achieves this by separating the algorithm from the objects on which it operates. Important Topics for the Visitor Pattern in JavaScript Desi
12 min read
Proxy Method Design Pattern in Java
A Proxy Method or Proxy Design Pattern is a structural design pattern that provides a surrogate or placeholder for another object to control access to it. This pattern involves creating a new class, known as the proxy, which acts as an intermediary between a client and the real object. The proxy obj
9 min read
Mediator Design Pattern in Java
The mediator design pattern defines an object that encapsulates how a set of objects interact. The Mediator is a behavioral pattern (like the Observer or the Visitor pattern) because it can change the program's running behavior. We are used to see programs that are made up of a large number of class
4 min read