BackendBench
Coffee

Unravel › Java concepts › Design patterns and architecture

Java language

Visitor pattern

The visitor pattern lets you add new operations to a family of classes without changing them: each element has an accept(visitor) method that calls back visitor.visit(this), and the visitor decides what to do for each type.

Learn these first

At a glance

Mental model

A museum with many exhibits and many kinds of visitors (tourist, inspector, photographer).

What happens, in order
  1. 1The element types implement accept(Visitor v) { v.visit(this); }The Visitor interface has one visit method per element type (visit(Circle), visit(Square)).
  2. 2A new operation (compute area, export to XML, draw) is a new visitor class, and no element class is touchedAdding a new element type needs a change in every visitor, which is the trade-off.
  3. 3Seen in the JDK: Files.walkFileTree with SimpleFileVisitor, annotation processors, and compiler tree visitors (javac, Spring Expression Language)
  4. 4With sealed types and pattern-matching switch, you get the same result with much less ceremony: switch (shape) { case Circle c -> ...; case Square s -> ...; }
Remember
Watch out
Applying it to a hierarchy that changes oftenForgetting to update every visitor when adding an element typeUsing it where a sealed type plus switch would be simpler
Example (highlighted lines explain it)
public class Shapes {  interface Visitor<R> { R visit(Circle c); R visit(Square s); }  interface Shape { <R> R accept(Visitor<R> v); }  record Circle(double r) implements Shape { public <R> R accept(Visitor<R> v) { return v.visit(this); } }  record Square(double side) implements Shape { public <R> R accept(Visitor<R> v) { return v.visit(this); } }  static class AreaVisitor implements Visitor<Double> {    public Double visit(Circle c) { return Math.PI * c.r() * c.r(); }    public Double visit(Square s) { return s.side() * s.side(); }  }}
Read the full explanation (about 1 min)

The visitor pattern lets you add new operations to a family of classes without changing them: each element has an accept(visitor) method that calls back visitor.visit(this), and the visitor decides what to do for each type.

A mental model

A museum with many exhibits and many kinds of visitors (tourist, inspector, photographer). Each exhibit welcomes any visitor with "come in", and the visitor behaves in their own way at each type of exhibit.

How it works

The element types implement accept(Visitor v) { v.visit(this); }. The Visitor interface has one visit method per element type (visit(Circle), visit(Square)).

A new operation (compute area, export to XML, draw) is a new visitor class, and no element class is touched. Adding a new element type needs a change in every visitor, which is the trade-off.

Seen in the JDK: Files.walkFileTree with SimpleFileVisitor, annotation processors, and compiler tree visitors (javac, Spring Expression Language).

With sealed types and pattern-matching switch, you get the same result with much less ceremony: switch (shape) { case Circle c -> ...; case Square s -> ...; }.

Going deeper

Double dispatch is the idea: the first dispatch is on the element (accept), the second on the visitor (visit), so the choice depends on both types, which Java does not do by itself.

Use it for stable hierarchies (an AST, a file tree) with many changing operations. For an open set of elements, use polymorphic methods instead.

Under the hood

Plain virtual calls: shape.accept(v) is dispatched on the shape's run-time class; inside it, v.visit(this) is resolved at compile time to the overload for that exact class.

Common mistakes

  • Applying it to a hierarchy that changes often.
  • Forgetting to update every visitor when adding an element type.
  • Using it where a sealed type plus switch would be simpler.

How Unravel recognises it

When you paste code, Unravel looks for these signs of visitor pattern. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is Visitor pattern?

The visitor pattern lets you add new operations to a family of classes without changing them: each element has an accept(visitor) method that calls back visitor.visit(this), and the visitor decides what to do for each type.

What are the most common mistakes with Visitor pattern?

Applying it to a hierarchy that changes often. Forgetting to update every visitor when adding an element type. Using it where a sealed type plus switch would be simpler.

How can I see Visitor pattern in real code?

Paste your own Java into Unravel and it will point out where visitor pattern appears, explain how it works at the detail level you choose, and draw the flow of the code around it.