How does Visitor help add new operations without modifying classes?
The Visitor pattern lets you add new operations on objects without changing their classes, because all the logic of the new actions is moved into an external object, the visitor.
1. The Problem Without Visitor
Suppose there are several types of elements:
class Circle { void draw() { ... } }
class Square { void draw() { ... } }Now you need to add new operations:
- exporting to PDF,
- calculating area,
- validating parameters.
Without Visitor, you'd have to add new methods to every class:
class Circle {
void draw() { ... }
void exportToPDF() { ... } // added
void calculateArea() { ... } // added
}The problems:
- existing classes have to be edited every time;
- with dozens of operations and elements, the code grows quickly;
- the Open/Closed principle is violated (classes are open to modification).
2. How Visitor Solves This
Visitor moves all the "actions" out of the classes themselves and into external objects, visitors. Now every new algorithm is created as a new class, instead of new methods inside the elements.
3. Structure
interface Shape {
void accept(ShapeVisitor visitor);
}
interface ShapeVisitor {
void visit(Circle c);
void visit(Square s);
}
class Circle implements Shape {
public void accept(ShapeVisitor visitor) { visitor.visit(this); }
}
class Square implements Shape {
public void accept(ShapeVisitor visitor) { visitor.visit(this); }
}4. Adding New Operations
To add, for example, exporting to PDF, you just need to create a new visitor:
class ExportToPDFVisitor implements ShapeVisitor {
public void visit(Circle c) {
System.out.println("Exporting a circle to PDF");
}
public void visit(Square s) {
System.out.println("Exporting a square to PDF");
}
}For another operation (for example, calculating area), a different visitor:
class AreaCalculationVisitor implements ShapeVisitor {
public void visit(Circle c) { System.out.println("Calculating the circle's area"); }
public void visit(Square s) { System.out.println("Calculating the square's area"); }
}The elements (Circle, Square) stay the same, they just "accept" the visitor.
5. Usage
List<Shape> shapes = List.of(new Circle(), new Square());
// Add any new operation without changing the Shape classes
ShapeVisitor exportVisitor = new ExportToPDFVisitor();
ShapeVisitor areaVisitor = new AreaCalculationVisitor();
for (Shape shape : shapes) {
shape.accept(exportVisitor);
shape.accept(areaVisitor);
}6. Why This Works
- The elements only know how to accept a visitor (
accept()), but don't know what it does with them. - The visitor implements all the specific operations for each element type.
- Adding a new operation = a new
Visitor, without touchingShape,Circle,Square.
7. The Principle Being Implemented
Visitor embodies the Open/Closed principle:
The element classes are closed for modification, but open for extension through new visitors.
Conclusion
Visitor lets you add new operations without changing the classes of the objects themselves, because:
- All the logic of the new actions is moved into external classes (visitors).
- The elements only provide an entry point, the
accept()method. - Adding new behavior = creating a new visitor, not changing existing classes.
Summary:
Visitor moves changes from inside classes into an external behavior layer, keeping the structure stable and the system flexible.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.