🎯 什麼情境該想到我
當你「有一個由多種元素組成、而且結構相對穩定的物件結構,卻常常要對它新增各種操作」的時候(例如在語法樹 AST 上跑多種分析、對一批元素做多種匯出格式),又不想每加一種操作就去改每個元素類別,想把這些操作集中管理。
⚙️ 怎麼用(步驟 / 公式)
意圖:表示一個作用於某物件結構中各元素的操作。訪問者讓你可以在不改變各元素類別的前提下,定義作用於這些元素的新操作。
主要參與者 / 結構:
- Visitor(訪問者介面):對每一種具體元素宣告一個
visitXxx(element)。 - ConcreteVisitor(具體訪問者):一種操作=一個訪問者,實作對各元素的處理。
- Element(元素介面):宣告
accept(visitor)。 - ConcreteElement(具體元素):
accept()內回呼visitor.visitXxx(this)。 - ObjectStructure(物件結構):能列舉其元素,讓訪問者逐一造訪。
做法要點:
- 每個元素實作
accept(visitor),在裡面呼叫visitor對應自己型別的方法(double dispatch,雙重分派)。 - 想新增一種操作,就寫一個新的具體訪問者,完全不動元素類別。
- 走訪物件結構,對每個元素呼叫
accept(),把操作邏輯集中在訪問者裡。
🧪 我實際套用的紀錄
- (待填)
⚠️ 注意 / 什麼時候不適用
- 元素類別若常常增減就不適用:每加一種新元素,所有訪問者都得改(加一個
visitXxx)。 - 為了讓訪問者拿到需要的資料,元素往往得多開放內部,容易破壞封裝。
- 只有一兩種操作、或結構還不穩定時,直接把方法寫在元素類別上更簡單。
🔗 相關工具
- 組合模式 Composite(訪問者常用來對組合出的樹狀結構施加操作)
- 迭代器模式 Iterator(迭代器負責走到每個元素,訪問者負責對每個元素做事)
- 直譯器模式 Interpreter(想在語法樹上加多種分析/操作時,常搭配訪問者)
- 工具-針對介面編程(元素與訪問者透過介面互動)
- 工具-封裝變化點(把「會不斷新增的操作」封裝成一個個訪問者)
- 設計模式