Visitor Pattern – Adding Operations Without Changing Classes

🔥 The Problem Without Visitor Pattern

Imagine you have a set of objects (e.g., different types of employees), and you want to perform new unrelated operations on them (e.g., calculating tax, generating reports).

Without Visitor:

  • You’d add methods to the classes every time you want a new operation.
  • This breaks the Single Responsibility Principle.
  • It forces modification of existing classes, violating Open/Closed Principle.


✅ What Visitor Pattern Does

Visitor lets you add new operations to a group of classes without changing them.

It does this by:

  • Defining a Visitor interface with a visit method for each class type.
  • Each element class accepts a Visitor object and calls back the appropriate visit method.


💡 Real-World Analogy

Think of a museum visitor: they visit different exhibits and perform different actions like taking photos, taking notes, or buying souvenirs without altering the exhibits themselves.


🧑💻 Java Example: Employees and Operations

1. Element Interface

interface Employee {
    void accept(Visitor visitor);
}        

2. Concrete Elements

class Developer implements Employee {
    private String name;
    private int experienceYears;

    public Developer(String name, int experienceYears) {
        this.name = name;
        this.experienceYears = experienceYears;
    }

    public String getName() { return name; }
    public int getExperienceYears() { return experienceYears; }

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

class Manager implements Employee {
    private String name;
    private int teamSize;

    public Manager(String name, int teamSize) {
        this.name = name;
        this.teamSize = teamSize;
    }

    public String getName() { return name; }
    public int getTeamSize() { return teamSize; }

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

3. Visitor Interface

interface Visitor {
    void visit(Developer developer);
    void visit(Manager manager);
}        

4. Concrete Visitors (Operations)

class TaxVisitor implements Visitor {
    @Override
    public void visit(Developer developer) {
        System.out.println("Calculating tax for Developer " + developer.getName());
        // tax logic here
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("Calculating tax for Manager " + manager.getName());
        // tax logic here
    }
}

class ReportVisitor implements Visitor {
    @Override
    public void visit(Developer developer) {
        System.out.println("Generating report for Developer " + developer.getName());
        // report logic here
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("Generating report for Manager " + manager.getName());
        // report logic here
    }
}        

5. Client Usage

public class Client {
    public static void main(String[] args) {
        List<Employee> employees = List.of(
            new Developer("Alice", 5),
            new Manager("Bob", 10)
        );

        Visitor taxVisitor = new TaxVisitor();
        Visitor reportVisitor = new ReportVisitor();

        for (Employee emp : employees) {
            emp.accept(taxVisitor);
            emp.accept(reportVisitor);
        }
    }
}        

💡 Why Visitor Pattern is Useful

  • Add new operations without modifying existing classes.
  • Keeps element classes focused on their core responsibilities.
  • Supports adding many unrelated operations easily.
  • Useful in compilers, UI frameworks, or any system with many object types needing multiple operations.


Without Visitor, adding a new operation means editing all element classes.

With Visitor, you add a new Visitor implementation — no change to element classes.


📌 When to Use Visitor Pattern

  • When you have many distinct operations to perform on a set of objects.
  • When object structure is stable but operations frequently change.
  • When you want to separate algorithms from the object structure.


To view or add a comment, sign in

Explore content categories