iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
The Visitor pattern lets you add operations over a set of Java object types without putting each operation into those types. Each concrete element implements accept, which calls a matching, typed visitor method. That makes Visitor a good fit when the element types are relatively stable and you expect to add operations such as export, validation, or reporting; it is less attractive when the types themselves change often.
What the Visitor pattern does
Visitor represents an operation over elements in an object structure while keeping that operation outside the element classes. Instead of adding export, validation, and analysis methods to every shape, for example, you can implement each operation in a separate visitor. This follows the pattern’s stated intent to add operations without changing the element classes; see the Project Management Institute’s overview.
The usual arrangement has an element interface, a visitor interface with one method for each concrete element type, concrete elements that implement accept, and concrete visitors that perform different operations. The visitor knows the element types it handles, while an element’s accept method routes the call to the corresponding typed visitor method. Refactoring.Guru illustrates this Java structure with shapes and an XML-export visitor in its Java example.
Recommended Free Tools
A small Java example
This illustrative sketch shows the key contract for two element types. It uses a generic result type so a visitor can return a value; choose a return type and any additional context parameter to suit the operation.
interface Shape {
<R> R accept(ShapeVisitor<R> visitor);
}
interface ShapeVisitor<R> {
R visitCircle(Circle circle);
R visitRectangle(Rectangle rectangle);
}
final class Circle implements Shape {
@Override
public <R> R accept(ShapeVisitor<R> visitor) {
return visitor.visitCircle(this);
}
}
final class Rectangle implements Shape {
@Override
public <R> R accept(ShapeVisitor<R> visitor) {
return visitor.visitRectangle(this);
}
}
A concrete visitor implements ShapeVisitor<R> and supplies the operation separately for circles and rectangles. For example, an export visitor could produce text for each shape, while a validation visitor could check shape-specific rules. The elements need only provide the acceptance hook and whatever data the operations are meant to use.
Why accept matters: double dispatch
Java does not choose an overloaded method according to an argument’s runtime class. Overload resolution uses the argument’s compile-time type. If a variable is declared as Shape, calling visitor.visit(shape) selects an overload applicable to Shape, even when the object is a Circle. Refactoring.Guru explains this distinction in its discussion of Visitor and double dispatch.
Rank #2
The classic pattern connects compile-time overloading with runtime overriding in two steps:
Free tools Windows power users keep installed
One-click scans. No signup required.
shape.accept(visitor)is dynamically dispatched to the concrete element’s implementation.- That implementation calls a specifically typed method such as
visitor.visitCircle(this). Becausethisis statically aCirclethere, Java selects the circle overload.
This is commonly called double dispatch: the concrete element determines which visitor method is called, and the visitor implementation determines what operation that method performs. Without accept, simply overloading visit does not provide the same runtime-type routing.
What changes are easy—and what changes are costly
Visitor favors adding operations over adding element types. The trade-off is central to deciding whether the pattern fits, as described by Refactoring.Guru and the PMI overview.
| Change | Typical effect |
|---|---|
| Add an operation | Add another visitor implementation; the element classes and visitor interface can often remain unchanged. |
| Add an element type | Add a method to the visitor contract and update concrete visitor implementations to handle the new type. |
That cost is not only maintenance overhead. The visitor interface depends on the concrete element types, and visitor implementations may need information that the elements do not expose. Giving visitors access to private state can weaken encapsulation; exposing only public data may make an operation awkward or impossible. Decide deliberately what belongs in the element API rather than adding broad access just to make a visitor convenient.
Rank #4
When Visitor is a good fit
- Your object structure has several distinct concrete element types.
- You need multiple operations that behave differently for those types, such as export, validation, reporting, or analysis.
- You expect the set of operations to grow more often than the set of element types.
- The data needed by those operations can be exposed through an intentional API without undermining encapsulation.
For a small hierarchy and one simple operation, a conditional can be clearer than a visitor interface and a family of visitor classes. Be cautious if element types are added frequently: every new type may require changes across the visitor contract and its implementations. Refactoring.Guru characterizes the pattern as relatively uncommon because of its complexity and narrower applicability; that is a qualitative observation, not a measured usage rate, in its Java discussion.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteVisitor, type switches, and Java’s own API
A visitor is not automatically better than a type switch or pattern matching. Compare the approaches against how often operations and types change, whether the set of types is closed or open, how much encapsulation matters, and whether you need exhaustive handling. Visitor makes the operation-versus-type evolution trade-off explicit; there is no universal winner independent of those design conditions.
Best Value
The JDK provides a visitor-style example in Oracle’s Java SE 26 TypeVisitor<R,P> API, described as “A visitor of types, in the style of the visitor design pattern.” It is used when the kind of type is unknown at compile time; a type’s accept method invokes the applicable visitXyz method. The API uses R for a result and P for an additional parameter, and documents Void for visitors that need neither a result nor a useful parameter.
Oracle’s Java SE 26 documentation also warns that new methods may be added as language structures evolve. For this API, it advises concrete visitor implementers to extend an appropriate abstract visitor class to reduce source incompatibility, while APIs should generally accept the visitor interface in their signatures. That is specific guidance for the JDK visitor API, not a blanket requirement for every application-level visitor. The same Java documentation page identifies its scope as Java SE 26 and JDK 26.
Refactoring.Guru also names java.nio.file.FileVisitor and SimpleFileVisitor among Java library examples in its Java example.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

