Patterns: behavior · 3 MIN READ

Visitor: new operations over a stable set of nodes

Understand the tradeoff between adding node types and adding operations.

Understand the tradeoff between adding node types and adding operations. Visitor separates operations from a stable object structure using dispatch through the node type. Trace the worked Go example, then compare the benefit with the cost before applying this design to your own project.

Behavioral pattern · A MAP OF THE IDEA

  1. Node accepts an operation
  2. Node dispatches by its concrete kind
  3. Visitor implements traversal behavior

Useful when

  • Node kinds are stable and operations grow
  • A tree needs multiple independent passes

Watch out

  • New node kinds affect every visitor
  • Large visitor interfaces increase maintenance

Implementation & operation cost: High

Fit depends on the task

Small tool or CLI2/5
Domain-rich application3/5
Independent distributed services2/5

Editorial suitability, not benchmarks or a universal ranking. Styles describe different axes and can be combined.

01

The design decision

Visitor separates operations from a stable object structure using dispatch through the node type. It is useful for syntax trees with many passes. In Go, a type switch may be simpler for a small local tree; classic Visitor becomes costly when node kinds change often.

02

A complete Go example

Read this program from the entry point and follow the calls shown in the diagram. The output is included at the end so you can check the behavior without a compiler.

go
package main

import (
	"fmt"
)

type Visitor interface {
	Number(Number) int
	Add(Add) int
}
type Node interface{ Accept(Visitor) int }
type Number int

func (n Number) Accept(v Visitor) int { return v.Number(n) }

type Add struct{ Left, Right Node }

func (a Add) Accept(v Visitor) int { return v.Add(a) }

type Evaluate struct{}

func (Evaluate) Number(n Number) int { return int(n) }
func (v Evaluate) Add(a Add) int     { return a.Left.Accept(v) + a.Right.Accept(v) }

func main() {
	tree := Add{Left: Number(2), Right: Number(3)}
	fmt.Println(tree.Accept(Evaluate{}))
}

// Output:
// 5
Read the code

Each node dispatches to its matching visitor method. Evaluate traverses child nodes to compute five without putting evaluation policy inside Add. A second visitor could count nodes while using the same node structure.

03

Tradeoffs and the simpler alternative

Adding a new visitor operation is straightforward, but adding a new node kind changes the Visitor interface and every implementation. This is the main tradeoff. Prefer a switch when the structure and operations are both small and local.

TAKE THIS WITH YOU

Adds operations easily but new node kinds affect visitors. Adding a new visitor operation is straightforward, but adding a new node kind changes the Visitor interface and every implementation. This is the main tradeoff. Prefer a switch when the structure and operations are both small and local.

Check your understanding

Which statement best describes Visitor: new operations over a stable set of nodes?

Go to the source

Progress stays in this browser. No account needed.