The Visitor Pattern is a behavioral design pattern that allows new operations to be added to an existing object structure without modifying the classes of the objects being operated on.

Instead of placing every operation inside the objects themselves, the Visitor Pattern moves related operations into separate visitor classes. Each visitor implements a specific operation and "visits" each element in the object structure.

This approach follows the Open/Closed Principle by allowing new operations to be introduced without changing existing element classes.

The Visitor Pattern is commonly used in compilers, abstract syntax trees (ASTs), document processing, report generation, and object structure traversal.

Structure

The Visitor Pattern consists of the following participants.

1. The Visitor declares visit methods for each concrete element.
2. The Concrete Visitor implements the operations performed on each element.
3. The Element declares the accept() method that accepts a visitor.
4. Concrete Elements implement the accept() method and allow visitors to operate on them.
5. The Client creates visitors and applies them to the object structure.

Java Implementation

Suppose an application generates reports for different employee types. Instead of placing reporting logic inside each employee class, a visitor is used to perform the reporting operation.

Create the visitor interface.
public interface EmployeeVisitor {
    void visit(Developer developer);
    void visit(Manager manager);
}
Create the element interface.
public interface Employee {
    void accept(EmployeeVisitor visitor);
}
Create the concrete elements.
public class Developer implements Employee {
    @Override
    public void accept(EmployeeVisitor visitor) {
        visitor.visit(this);
    }
}
public class Manager implements Employee {
    @Override
    public void accept(EmployeeVisitor visitor) {
        visitor.visit(this);
    }
}
Create the concrete visitor.
public class ReportVisitor implements EmployeeVisitor {
    @Override
    public void visit(Developer developer) {
        System.out.println("Generating developer report.");
    }
    @Override
    public void visit(Manager manager) {
        System.out.println("Generating manager report.");
    }
}
The client applies the visitor.
public class Main {
    public static void main(String[] args) {
        EmployeeVisitor visitor = new ReportVisitor();
        Employee developer = new Developer();
        Employee manager = new Manager();

        developer.accept(visitor);
        manager.accept(visitor);
    }
}
Output:
Generating developer report.
Generating manager report.

How It Works?

The client creates a ReportVisitor object containing the operation that will be performed on different employee types.

Each employee implements the accept() method. When invoked, it passes itself to the visitor by calling the appropriate visit() method. This enables the visitor to determine the concrete type of the element without using conditional statements or type checks.

Different visitors can implement different operations, such as report generation, salary calculation, auditing, or exporting data, while the employee classes remain unchanged.

This separation allows new operations to be added easily without modifying the existing object hierarchy.

Advantages

1. New operations can be added without modifying existing element classes.
2. Related operations are grouped together inside visitor classes.
3. It separates business operations from the object structure.
4. It simplifies implementing multiple operations on the same set of objects.

Disadvantages

1. Adding a new element type requires changes to every visitor implementation.
2. The pattern introduces additional interfaces and classes.
3. It can become complex when the object hierarchy changes frequently.

JDK Examples

The Visitor Pattern appears throughout the Java ecosystem.

1. The javax.lang.model.element.ElementVisitor interface is used by the Java Compiler API to process different kinds of program elements.

2. The javax.lang.model.type.TypeVisitor interface provides visitor-based processing for different Java type representations.

Summary

The Visitor Pattern separates operations from the objects on which they operate by encapsulating each operation inside a visitor.

By allowing new operations to be added without modifying existing classes, the pattern improves extensibility and keeps object structures focused on representing data rather than implementing every possible operation.
Nagesh Chauhan

Nagesh Chauhan

Principal Software Engineer • Java • Python • Distributed Systems • AI/ML

Principal Software Engineer with 14+ years of experience designing and delivering large-scale distributed systems, cloud-native applications, and AI-powered platforms.

Passionate about solving complex engineering problems using strong data structures and algorithms, along with expertise in Java, Spring Boot, Python, System Design, Microservices, Cloud, Kafka, Elasticsearch, and Generative AI.

Share this Article

💬 Comments

Join the Discussion