Catalog / Behavioral Patterns / Visitor Pattern
BEHAVIORAL

Visitor Pattern

Separate an algorithm from the object structure on which it operates.

Intent & Objective

Define a new operation without changing the classes of the elements on which it operates by using double dispatch.

πŸ‘₯ Real-World Human Analogies & Social Roles
3 Intuitive Scenarios
Museum Tour Guide Cultural Exhibits

"The museum (structure) has exhibits (elements). The guide (visitor) walks through explaining each exhibit differently without modifying the exhibits themselves."

Corporate Tax Auditor Financial Compliance

"An auditor visits employees, departments, and financial records applying inspection checks, leaving the company structure completely unchanged."

Doctor Visiting Hospital Patients Medical Care

"The doctor visits patients in different wards, diagnosing and prescribing treatments without modifying the hospital building structure."

The Problem

Polluting element classes with dozens of unrelated algorithms (export to XML, compute export tax, render 3D mesh, validate semantics).

The Solution

Place the new behavior into a separate Visitor class instead of trying to integrate it into existing classes. The element classes implement an `accept(Visitor)` method (Double Dispatch).

Key Participants & Architectural Roles

Visitor Interface
Declares a set of visiting methods for each concrete element class
Concrete Visitor
Implements several versions of the same algorithm tailored for all element classes
Element Interface
Declares an `accept()` method taking the visitor
Concrete Element
Implements `accept()` by calling `visitor.visitConcreteElement(this)`

Code Samples (Traditional OOP vs Functional Programming)

Available in C++, Python, and Java

Paradigm Contrast: Traditional OOP vs Functional / Data-Oriented

In OOP, Visitor simulates double dispatch via `accept(visitor)` and `visit(element)`. In Functional Programming, Visitor is native: it is simply Pattern Matching over Algebraic Data Types / Sum Types or catamorphisms / folds.

Advantages

  • βœ“ Open/Closed Principle: introduces a new behavior without altering existing element classes
  • βœ“ Single Responsibility Principle: moves multiple versions of the same behavior into the same class
  • βœ“ Can accumulate useful state as it traverses the element structure

Trade-offs

  • βœ— Adding a new element class requires updating all visitor classes and interfaces

When to Apply

  • β†’ When you need to perform an operation on all elements of a complex object structure (such as an Abstract Syntax Tree)
  • β†’ When you want to clean up business logic of auxiliary behaviors

When to Avoid

  • ! When the element hierarchy changes frequently (adding new element classes breaks every visitor)