Visitor Pattern — Design Patterns

Visitor memisahkan algoritma dari struktur data yang diproses. Kamu bisa menambah operasi baru tanpa mengubah class struktur data. Kapan berguna: Struktur data

Visitor memisahkan algoritma dari struktur data yang diproses. Kamu bisa menambah operasi baru tanpa mengubah class struktur data.

Kapan berguna:

Contoh klasik: AST (Abstract Syntax Tree) traversal

Parser menghasilkan tree node: NumberLiteral, Variable, BinaryOp. Kita ingin beberapa operasi: evaluate, print, optimize, typecheck.

Tanpa Visitor:

class NumberLiteral {
  constructor(value) { this.value = value; }
  evaluate() { return this.value; }
  print() { return String(this.value); }
  optimize() { return this; }
  typecheck() { return "number"; }
  // Tiap operasi baru → edit SEMUA class node
}

Dengan Visitor:

class NumberLiteral {
  constructor(value) { this.value = value; }
  accept(visitor) { return visitor.visitNumber(this); }
}

class BinaryOp {
  constructor(op, left, right) {
    this.op = op;
    this.left = left;
    this.right = right;
  }
  accept(visitor) { return visitor.visitBinaryOp(this); }
}

// Operasi jadi class terpisah
class Evaluator {
  visitNumber(node) { return node.value; }
  visitBinaryOp(node) {
    const l = node.left.accept(this);
    const r = node.right.accept(this);
    return node.op === "+" ? l + r : l - r;
  }
}

class Printer {
  visitNumber(node) { return String(node.value); }
  visitBinaryOp(node) {
    return `(${node.left.accept(this)} ${node.op} ${node.right.accept(this)})`;
  }
}

// Penggunaan:
const tree = new BinaryOp("+", new NumberLiteral(1), new NumberLiteral(2));
tree.accept(new Evaluator()); // 3
tree.accept(new Printer());   // "(1 + 2)"

Double dispatch — inti trick:

Kelebihan:

Kekurangan:

JavaScript/TypeScript alternative (tidak perlu strict Visitor):

// Tipe tag-based dispatch via switch (lebih idiomatic di TS)
type Node =
  | { type: "number"; value: number }
  | { type: "binary"; op: string; left: Node; right: Node };

const evaluate = (n: Node): number => {
  switch (n.type) {
    case "number": return n.value;
    case "binary":
      const l = evaluate(n.left);
      const r = evaluate(n.right);
      return n.op === "+" ? l + r : l - r;
  }
};

TypeScript exhaustiveness check memastikan semua case ter-handle. Ini adalah functional equivalent dari Visitor — sama benefit dengan lebih sedikit ceremony.

Kapan pakai Visitor murni vs tag dispatch: