100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

Visitor Pattern

AdvancedTechnique595 learners

The Visitor Pattern is a behavioral design pattern that lets you define a new operation on a set of related classes without modifying those classes, by moving the operation into a separate visitor object that each class accepts via a…

Definition

The Visitor Pattern is a behavioral design pattern that lets you define a new operation on a set of related classes without modifying those classes, by moving the operation into a separate visitor object that each class accepts via a double-dispatch call.

Overview

Cataloged by the Gang of Four, the Visitor Pattern solves a specific tension in object-oriented design: adding a new operation to a class hierarchy normally means editing every class in that hierarchy, which can be undesirable if the classes are stable, shared, or owned by another team, and if new operations are added more often than new classes. Visitor inverts this by defining an `accept(visitor)` method on each element class that simply calls back into the visitor with itself (`visitor.visitConcreteElementA(this)`), a technique called double dispatch. The actual behavior for each element type lives in the corresponding `visit*` method on the visitor class, so adding a whole new operation across the hierarchy means writing one new visitor class rather than touching every element class. Visitor is especially prevalent in compiler and interpreter design, where an abstract syntax tree's node classes (numbers, identifiers, binary expressions) are relatively fixed, but many different operations need to run over that tree: type checking, code generation, pretty-printing, optimization passes, and static analysis. Each of these becomes its own visitor class implementing a `visit` method per node type, keeping the AST node classes themselves free of unrelated logic — a clean separation of data structure from algorithm. Tools like ESLint, TypeScript's compiler, and many linters and static analyzers are built around visitor-style AST traversal. The pattern's tradeoff is the mirror image of its benefit: while adding new operations is easy, adding a new element type to the hierarchy is expensive, since every existing visitor class must be updated with a new `visit` method for that type. This makes Visitor a good fit when the class hierarchy is stable and the set of operations grows over time, and a poor fit when new element types are added frequently. Modern implementations sometimes soften this rigidity using generics, default methods, or pattern matching (as in visitor-like exhaustive switch statements in languages such as Rust or TypeScript with discriminated unions).

Key Concepts

  • Separates algorithms/operations from the object structure they operate on
  • Uses double dispatch: accept() on elements calls back into visit() on the visitor
  • New operations added by creating new visitor classes, not editing elements
  • Widely used for AST traversal in compilers, linters, and interpreters
  • Keeps element/node classes focused purely on data, not behavior
  • Trade-off: adding new element types requires updating every visitor
  • Often paired with Composite pattern for tree-structured object graphs
  • Modern languages emulate it via pattern matching / discriminated unions

Use Cases

Traversing and analyzing abstract syntax trees in compilers/linters
Implementing multiple independent operations over a fixed class hierarchy
Building code generators, pretty-printers, or static analyzers
Serializing heterogeneous object graphs to different formats (JSON, XML)
Implementing type-checking or validation passes over parsed documents
Rendering different views/exports of a shared document object model

Frequently Asked Questions