Visitor: add operations over stable types
Picture
A tree contains numbers and additions. Evaluation and formatting are two different operations over those same elements.
Predict
Which change does Visitor make easier?
Walk through the small example
New operations over stable types. Visitor deliberately favors one direction of change.
Mental model and complete Python solution
Number and Add select the appropriate visitor operation through accept. Evaluator and Formatter each implement a complete operation over the same tree. This double-dispatch style separates operations from elements. Python pattern matching or singledispatch may be simpler in some codebases; the stable-type-set tradeoff still matters.
What the function promises: The finite expression tree contains Number and Add nodes. Evaluation returns a number; formatting returns parenthesized text.
class Number:
def __init__(self, value):
self.value = value
def accept(self, visitor):
return visitor.number(self)
class Add:
def __init__(self, left, right):
self.left, self.right = left, right
def accept(self, visitor):
return visitor.add(self)
class Evaluator:
def number(self, node):
return node.value
def add(self, node):
return node.left.accept(self) + node.right.accept(self)
class Formatter:
def number(self, node):
return str(node.value)
def add(self, node):
return f"({node.left.accept(self)} + {node.right.accept(self)})"
tree = Add(Number(2), Number(3))
assert tree.accept(Evaluator()) == 5
assert tree.accept(Formatter()) == "(2 + 3)"
Work and storage: O(tree size) evaluation; formatting can incur extra string-copying cost on deeply skewed trees.
When to recognize it: Adding an operation is convenient. Adding a new element type requires updating visitors that promise to handle every type.
Check before applying it: Frequent new element types can make Visitor expensive to maintain.
Change one rule
We add multiplication. What needs review?
See what changes
The new node’s dispatch and every visitor promising complete support. Unsupported cases should fail explicitly rather than silently producing incomplete output.
Connect
Composite: treat a tree uniformly: A composite supplies the tree of stable element types.
Template Method: fix the workflow: Compare a separate operation object with overridable workflow steps.