Last Updated: February 24, 2026
The Visitor Design Pattern is a behavioral pattern that lets you add new operations to existing object structures without modifying their classes.
It achieves this by allowing you to separate the algorithm from the objects it operates on.
It’s particularly useful in situations where:
if-else or instanceof checks.Let’s walk through a real-world example to see how we can apply the Visitor Pattern to cleanly separate behavior from structure and make our system easier to extend without touching existing classes.
Imagine you are building a vector graphics editor that supports multiple shape types:
CircleRectangleEach shape is part of a common hierarchy and must support a variety of operations, such as:
The simplest approach is to add all of these methods to each shape class:
This solution seems fine for a couple of operations, but quickly becomes problematic as new operations or shape types are added.
Each shape class now contains multiple unrelated responsibilities: geometry calculations, drawing, serialization, and format exporting. This bloats the class and makes it harder to maintain.
If you need to add a new operation (e.g., generatePdf()), you must modify every class in the hierarchy, recompile everything, and risk breaking existing logic. This violates the Open/Closed Principle.
What if the shape classes are part of a third-party library or generated code? You cannot easily add new behavior directly.
We need a solution that lets us:
instanceof checks or using type switches to handle different shapesThis is exactly what the Visitor pattern is designed to solve.
The Visitor Design Pattern lets you separate algorithms from the objects on which they operate. It enables you to add new operations to a class hierarchy without modifying the classes themselves.
Two characteristics define the pattern:
this, which resolves the element's concrete type at compile time. This two-step dispatch is what makes the pattern work without instanceof checks.Think about a home inspection. You have a house with different components: plumbing, electrical wiring, structural framing, and HVAC. Each specialist (a plumber, an electrician, a structural engineer, an HVAC technician) "visits" the house and inspects only what they understand.
The house does not need to know how to evaluate its own plumbing or wiring. It just opens the door and lets each inspector do their job. Adding a new type of inspection (say, a fire safety audit) does not require remodeling the house. You just bring in a new inspector.
The Visitor pattern works the same way: the elements (house components) accept visitors (inspectors), and new operations are new visitors.
Declares the accept(Visitor) method that every element in the object structure must implement. This is the entry point for the double dispatch mechanism.
The accept() method exists purely to enable double dispatch. Without it, the visitor would need instanceof checks to figure out the element's concrete type. With it, the element tells the visitor "I am a Circle" by calling visitor.visitCircle(this), and the correct overloaded method is invoked at compile time.
Circle, Rectangle)Each concrete element implements the accept() method by calling the visitor's corresponding visit method, passing this.
Declares a visit method for each concrete element type. This is the interface that all operations implement.
AreaCalculatorVisitor)Each concrete visitor implements the Visitor interface with a specific operation. One visitor might calculate areas, another might export to SVG, a third might validate constraints.
The Visitor workflow involves a two-step dispatch that routes execution to the right method based on both the element type and the visitor type.
Step 1: The client creates a concrete visitor (e.g., AreaCalculatorVisitor).
Step 2: The client iterates over the element collection and calls element.accept(visitor) on each one.
Step 3: Inside accept(), the element calls back the visitor's specific method: visitor.visitCircle(this) for a Circle, visitor.visitRectangle(this) for a Rectangle. This is the double dispatch: the element resolves its own type.
Step 4: The visitor's visitCircle() or visitRectangle() method runs, performing the operation using the element's data.
Step 5: To add a new operation, you create a new visitor class. No element classes change.
Let us refactor the graphics system using the Visitor pattern to perform two operations (area calculation and SVG export) without putting any operational logic inside the shape classes.
Here is the class diagram for the solution:
All shapes must accept a visitor.
Each shape class implements accept() and delegates to the visitor.
Each method corresponds to a shape type.
Now you can operate on the shape structure using any visitor.
JsonExporterVisitor) without touching shapesinstanceof or type-checking