Skip to main content

Visitor

Overview​

Add operations to object structures without changing their classes.

When to use​

  • You need to run multiple operations on a stable object structure.
  • Adding new operations is more common than adding new node types.

Java example​

interface Visitor {
void visit(TextNode node);
void visit(ImageNode node);
}

interface DocNode {
void accept(Visitor visitor);
}

class TextNode implements DocNode {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

class ImageNode implements DocNode {
public void accept(Visitor visitor) {
visitor.visit(this);
}
}

TypeScript example​

interface Visitor {
visitText(node: TextNode): void;
visitImage(node: ImageNode): void;
}

interface DocNode {
accept(visitor: Visitor): void;
}

class TextNode implements DocNode {
accept(visitor: Visitor): void {
visitor.visitText(this);
}
}

class ImageNode implements DocNode {
accept(visitor: Visitor): void {
visitor.visitImage(this);
}
}

Pros and cons​

Pros:

  • New operations can be added without modifying nodes.
  • Separates algorithms from object structure.

Cons:

  • Adding new node types requires updating all visitors.
  • Can be verbose.

Common pitfalls​

  • Using Visitor for small object graphs.
  • Forgetting to update all visitors after new nodes.