Visitor
Visitor separates operations from the object structure they act on, using double dispatch to add new behaviors over a stable class hierarchy without editing it. It makes adding operations easy but adding element types expensive.
Visitor is a behavioral pattern that lets you define new operations on a set of objects without changing the classes of those objects. It moves the operation into a separate visitor object and uses double dispatch so the correct behavior is selected based on both the visitor and the element type. This is valuable when you have a stable class hierarchy but a growing list of operations to perform over it.
How It Works
Each element in the structure implements an accept(visitor) method that calls back the visitor's visit method for its own type, for example visitor.visitCircle(this). The visitor interface declares one visit method per concrete element type. A concrete visitor implements all of them, carrying one operation across the whole hierarchy. The accept-then-visit handshake is double dispatch: the element's type selects the accept, and the visitor's type selects the visit, so the runtime resolves both dimensions.
Adding a new operation means writing one new visitor class, with no edits to the element classes. The trade is that adding a new element type forces a change to every visitor.
When to Use It
Use Visitor when an object structure contains many classes with differing interfaces and you want to run operations that depend on their concrete types, when the set of operations changes often while the set of element types is stable, or when you want to keep related behavior together in one place rather than scattered across element classes. Compilers, document object models, and abstract syntax trees are classic uses.
Trade-offs
Visitor trades flexibility in one dimension for rigidity in another: easy to add operations, costly to add element types. The double-dispatch boilerplate is verbose, and accessing element internals may force breaking encapsulation. It assumes a relatively closed hierarchy; if element types change frequently, the pattern hurts more than it helps. Languages with pattern matching or multimethods can express the same intent more concisely.
Related Patterns
Composite structures are a natural target for Visitor, which walks the tree applying an operation. Iterator can drive the traversal that feeds elements to the visitor. Interpreter often uses Visitor to evaluate, optimize, or print expression trees. Pattern matching, multimethods, and sealed type hierarchies with exhaustive switches are functional-style alternatives that achieve the same per-type dispatch with far less boilerplate, which is why many modern languages favor them over hand-written double dispatch.
Example
A shape hierarchy has Circle, Square, and Polygon. Rather than adding area, render, and export methods to each shape, define an AreaVisitor, a RenderVisitor, and an ExportVisitor. Each shape's accept dispatches to the right visit method via double dispatch. Introducing a new operation later adds one visitor and touches none of the shapes, but adding a new shape forces a new visit method on every visitor, which is the pattern's central trade. The textbook industrial use is a compiler: the abstract syntax tree is fixed while passes for type checking, optimization, and code generation are each a visitor over that tree. Document object models, scene graphs in graphics, and configuration trees use the same arrangement so that reporting, validation, and transformation passes can be added without disturbing the node classes.