Visitor Pattern - Operations on Complex Structures
Learn the Visitor pattern for defining operations on object structures. TypeScript examples for AST processing, document export, and report generation.
Detailed Explanation
Visitor Pattern
The Visitor pattern lets you add new operations to existing object structures without modifying the classes of the elements you operate on. It achieves this through double dispatch: the element accepts a visitor, and the visitor has a specific method for each element type.
Double Dispatch
In single dispatch (normal method calls), the method called depends on the runtime type of one object. Visitor implements double dispatch where the operation depends on the types of TWO objects: the element and the visitor.
interface DocumentVisitor {
visitParagraph(p: Paragraph): string;
visitImage(img: Image): string;
visitTable(table: Table): string;
}
class HtmlExporter implements DocumentVisitor {
visitParagraph(p: Paragraph) { return \`<p>\${p.text}</p>\`; }
visitImage(img: Image) { return \`<img src="\${img.url}" />\`; }
visitTable(table: Table) { return \`<table>...</table>\`; }
}
class MarkdownExporter implements DocumentVisitor {
visitParagraph(p: Paragraph) { return p.text + "\n"; }
visitImage(img: Image) { return \`\`; }
visitTable(table: Table) { return "| ... |\n"; }
}
When Visitor Excels
Visitor shines when the element hierarchy is stable (rarely add new element types) but you frequently add new operations. Compiler AST processing is the classic example: the node types (expressions, statements, declarations) are fixed, but you constantly add new analysis passes.
When to Avoid
If you frequently add new element types, every new type requires adding a method to every visitor. This is the fundamental tradeoff. For frequently changing element hierarchies, consider the Strategy pattern instead.
Accumulating State
Visitors can accumulate results as they traverse elements, making them ideal for aggregation operations: counting nodes, summing values, collecting statistics, or generating output.
Use Case
Visitor is essential for compiler AST processing (type checking, optimization, code generation as separate visitors), document format exporters (HTML, Markdown, PDF from the same document model), report generators that compute different metrics over the same data, and serialization systems.