訪問者 (Visitor)

★★★★★Studied

FromDesign Patterns (GoF)大話設計模式

📚 From the Books

訪問者 (Visitor)ConceptBehavioral

把「作用在一個物件結構上的操作」抽出來變成獨立的 visitor。要新增操作時只要新增一個 visitor,不必動到元素類別。代價是:元素型別固定,新增一種元素就得改所有 visitor。

🧠 When to Use

TIP

訊號:元素的型別集合很穩定,但你不斷要對它們加新操作(計價、匯出、檢查),而你不想每加一個操作就去戳每個元素類別。

⚖️ Structure & Variants

經典版 — double dispatch(accept + visit)
interface Shape { fun accept(v: Visitor) }
interface Visitor { fun visit(c: Circle); fun visit(s: Square) }

class Circle(val r: Int) : Shape { override fun accept(v: Visitor) = v.visit(this) }
class Square(val a: Int) : Shape { override fun accept(v: Visitor) = v.visit(this) }

class AreaVisitor : Visitor {                  // ← 新操作 = 新 visitor
    var total = 0.0
    override fun visit(c: Circle) { total += Math.PI * c.r * c.r }
    override fun visit(s: Square) { total += (s.a * s.a).toDouble() }
}

val shapes = listOf(Circle(2), Square(3))
val area = AreaVisitor().also { v -> shapes.forEach { it.accept(v) } }
  • accept 先依元素型別分派、再由多載 visitvisitor分派,這就是 double dispatch。
搭 Composite/Iterator 遍歷結構
  • 元素常是 Composite 樹;visitor 在 accept 裡遞迴造訪子節點。
  • 遍歷順序可以交給 Iterator,visitor 只管「每個節點做什麼」。
和「直接在元素上加方法」的取捨
  • 操作分散在元素類別:加元素容易、加操作要改每個類別
  • 改用 Visitor:加操作容易(新 visitor)、加元素痛(改所有 visitor)。選哪邊取決於哪一軸比較常變。

⚠️ Misuse & Anti-patterns

🔑 Takeaways

✍️ My Notes

No notes yet — jot your takeaways or Q&A here.

📖 Further Reading