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:
✅ What Visitor Pattern Does
Visitor lets you add new operations to a group of classes without changing them.
It does this by:
💡 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
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