第28章 男人和女人——訪問者模式
概念
訪問者模式表示一個作用於某對象結構中的各元素的操作。它可以使你在不改變元素類的前提下,定義作用於這些元素的新操作。
即:將類的操作,變爲特定對象,不同在增加新操作的時候修改類,而是增加新操作,就定義新對象,作爲數據參數傳遞給固定類。
場景
數據結構固定的情況下(例如人類只有男人和女人),將操作從數據結構中分離出來(比如成功、失敗等的反映定義成類對象傳給數據實現不同操作),將數據和其操作實現瞭解耦,又可以方便地讓操作擴展與演化。
其中,用到了雙分派技術,第一次是不同者的分派(不同操作的訪問類對象,傳遞給被操作的固定類對象),將不同的操作定義爲訪問者對象傳給正確的被操作對象,第二次是操作中不同動作的分派(不同的固定類對象,會以不同方式使用訪問者類),訪問者對象中對應不同的數據對象的操作供其調用。雙分派意味着執行的操作取決於請求的種類和接受者的類型。
實現
-
Visitor: 抽象訪問者類,單獨抽象出來表示對數據類對象的操作,其中會定義與對應固定數據子類對應的操作(如:
VisitA()
,VisitB()
) - ConcreteVisitor1,ConcreteVisitor2: 具體的訪問者子類,每一個子類表示對數據類的一種操作算法,每一個子類對象會實現對應數據子類的操作。
-
Element: 包含固定子類的抽象數據類,定義一個用來接收Visitor爲參數的接口(如:
accept()
),接收的Visitor便是對數據的操作。 -
ConcreteElementA,ConcreteElementB: 數據子類,實現
accept()
操作(一般就是調用Visit的對應操作),也包含一些自己的屬性方法。 - ObjectStructure, 對Element對象的枚舉,可以提供一個高層接口允許訪問者訪問它的元素,其中的
accept()
循環調用Element的accept()
。 -
Client: 如:創建ObjectStructure列表l,Element子對象e,將所有e加入l,創建Visitor子對象v,調用
l.accept(v)
以實現對所有e操作。
實現類圖:
總結起來即:
- 操作抽象類–訪問者類,包含 {A的操作,B的操作} 兩個接口;不同操作定義不同對象類,都繼承這個類形成各自的{A/B}一套操作。
- 元素抽象類–固定類,包含{接受}這一個接口;A類的{接受}調用訪問者中{A的操作},B類的{接受}調用訪問者中{B的操作}。
使用類圖:
雙分派,發生在 o.Accept(v)
調用的時候,假設o對象對應的固定類有A和B,而v對象對應了許多不同操作相關的訪問者類,第一次分派就是將v傳遞給了正確的o(是A或者B),第二次分配就是調用到正確的v函數(是A的操作還是B的操作)。
特徵
- 數據類型是穩定的不會變化(比如人只有男人和女人),這樣抽象出來的操作對象裏面的對應方法也是固定的不會變化,若數據變化會很麻煩。
- 支持數據的操作可變化,變化時可以定義和修改抽象出來的操作對象而不用改到具體的數據對象,體現了開放封閉原則。
舉例
- 操作:失敗(其中有:男人動作,女人動作)、成功(其中有男人動作,女人動作)
- 數據:男人(其中調用操作中的“男人動作”)、女人(其中調用操作中的“女人動作”)
- 使用:將操作傳遞給數據完成第一次分派;數據中的通用結構accept調用操作中的針對性動作。