Skip to main content

Visitor Pattern

Separate algorithms from objects they operate on

Pattern Overview

👋 Visitor Pattern

The Visitor Pattern separates algorithms from the objects on which they operate. It lets you define new operations without changing the classes of elements on which they operate.

Core Concepts

🔹 Visitor Interface - Declares visit methods for each element type
🔹 Concrete Visitors - Implement specific operations on elements
🔹 Element Interface - Declares accept method that takes visitor
🔹 Double Dispatch - Method calls depend on both visitor and element types

Real-World Applications

Compilers - AST traversal for code generation, optimization, type checking File Systems - Operations on files/directories (size calculation, security scanning) Document Processing - Export to different formats (HTML, PDF, XML) Game Engines - Operations on game objects (rendering, collision, AI)

Double Dispatch Magic

Single Dispatch - Method chosen based on receiver type only Double Dispatch - Method chosen based on both visitor and element types Result - Visitor pattern enables operation-specific behavior per element type

Implementation Benefits

Open/Closed Principle - Easy to add new operations without modifying elements
Single Responsibility - Operations grouped by visitor, not scattered across elements
Centralized Operations - Related operations live in same visitor class
Type Safety - Compile-time verification of visitor-element compatibility

Examples:
Perform different calculations and rendering operations on geometric shapes without modifying shape classes
Input:
createShapeCollection()
Output:
Shape operations executed
Analyze file system structure with size calculation and security scanning using visitor pattern
Input:
createFileSystem()
Output:
File system analyzed
Process abstract syntax tree for both code generation and mathematical evaluation with same structure
Input:
createAST()
Output:
Code generated and evaluated

Concepts

design patternssoftware architecturecode organizationobject-oriented programming

Complexity Analysis

Time:O(n) - visits each element once
Space:O(h) - recursion depth for tree structures

Implementation

shape-operations

Time: O(1) | Space: O(1)
// Visitor pattern for shape operations
interface Shape {
  accept(visitor: ShapeVisitor): string;
}

interface ShapeVisitor {
  visitCircle(circle: Circle): string;
  visitRectangle(rectangle: Rectangle): string;
  visitTriangle(triangle: Triangle): string;
}

class Circle implements Shape {
  constructor(public radius: number) {}

  accept(visitor: ShapeVisitor): string {
    return visitor.visitCircle(this);
  }

  getArea(): number {
    return Math.PI * this.radius * this.radius;
  }
}

class Rectangle implements Shape {
  constructor(public width: number, public height: number) {}

  accept(visitor: ShapeVisitor): string {
    return visitor.visitRectangle(this);
  }

  getArea(): number {
    return this.width * this.height;
  }
}

class AreaCalculator implements ShapeVisitor {
  visitCircle(circle: Circle): string {
    const area = Math.PI * circle.radius * circle.radius;
    return `Circle area: ${area.toFixed(2)}`;
  }

  visitRectangle(rectangle: Rectangle): string {
    const area = rectangle.width * rectangle.height;
    return `Rectangle area: ${area}`;
  }

  visitTriangle(triangle: Triangle): string {
    const area = 0.5 * triangle.base * triangle.height;
    return `Triangle area: ${area}`;
  }
}