PassFront
  1. PassFront
  2. База знаний
  3. Поведенческие паттерны

Что такое Visitor и double dispatch?

Поведенческие паттерны

Visitor выносит операции над иерархией классов в отдельный объект, а нужный метод выбирается двумя вызовами (double dispatch): сначала по типу элемента, затем по типу посетителя.

Зачем

  • Иерархия узлов стабильна (AST: Num, Add), а операций много: вычисление, печать, оптимизация, проверка типов. Новая операция — новый посетитель, классы узлов не трогаем.
  • Обратная сторона — expression problem: новый тип узла требует правки всех посетителей.

Double dispatch

Java, C# и JS/TS выбирают метод по динамическому типу только получателя (single dispatch); перегрузки visit(Add)/visit(Num) разрешаются статически, а в JS/TS их в рантайме нет вовсе. Visitor обходит это: node.accept(v) — выбор по узлу, внутри v.visitAdd(this) — по посетителю.

// Посетитель — объект с методами visitNum(n) и visitAdd(n)
class Num {
  constructor(value) { this.value = value; }
  accept(v) { return v.visitNum(this); }
}
class Add {
  constructor(left, right) { this.left = left; this.right = right; }
  accept(v) { return v.visitAdd(this); }
}
const evaluate = {
  visitNum: (n) => n.value,
  visitAdd: (n) => n.left.accept(evaluate) + n.right.accept(evaluate),
};
console.log(new Add(new Num(2), new Num(3)).accept(evaluate)); // 5

Коротко для собеседования

Visitor собирает операции над стабильной иерархией, например над узлами AST, в отдельных объектах, а связку accept → visitX использует как ручной double dispatch. Добавлять операции легко, а новый тип узла требует правки всех посетителей; в JS/TS часто проще switch по полю kind.

Другие вопросы раздела