定義:Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operations.(封裝一些作用於某種數據結構中的各元素的操作,它可以在不改變數據結構的前提下定義作用於這些元素的新的操作。)
訪問者模式的通用類圖如圖所示。
我們來看看這幾個角色的職責。
- IVisitor抽象訪問者:抽象類或者接口,聲明訪問者可以訪問哪些元素,具體到程序中就是visit方法的參數定義那些對象是可以被訪問的。
- Visitor具體訪問者:它影響訪問者訪問到一個類後該怎麼幹,要做什麼事情。
- Element抽象元素:接口或者抽象類,聲明接受哪一類訪問者訪問,程序上通過accept方法中的參數來定義的。
- ConcreteElement具體元素:實現accept方法,通常是visitor.visit(this),基本上都形成了一種模式了。
- ObjectStruture結構對象:元素產生者,一般容納在多個不同類、不同接口的容器,如List、Set、Map等,在項目中,一般很少抽象出這個角色。
1.訪問者模式的應用
1.1訪問者模式的優點
- 符合單一職責原則:具體元素角色也就是抽象類的兩個子類負責數據的加載,而Visitor類則負責報表的展現,兩個不同的職責非常明確地分離開來,各自演繹變化。
- 優秀的擴展性:由於職責分開,繼續增加對數據的操作是非常快捷的。
- 靈活性非常高。
1.2訪問者模式的缺點
- 具體元素對訪問者公佈細節:訪問者要訪問一個類就必然要求這個類公佈一些方法和數據,也就是說訪問者關注了其他類的內部細節,這是迪米特法則所不建議的。
- 具體元素變更比較困難。
- 違背了依賴倒置原則:訪問者依賴的是具體元素,而不是抽象元素,這破壞了依賴倒置原則,特別是在面向對象的編程中,拋棄了對接口的依賴,而直接依賴實現類,擴展比較難。
1.3訪問者模式的使用場景
- 一個對象結構包含很多類對象,它們有不同的接口,而你想對這些對象實施一些依賴於其具體類的操作,也就是用迭代器模式已經不能勝任的情景。
- 需要對一個對象結構中的對象進行很多不同並且不相關的操作,而你想避免讓這些操作“污染”這些對象的類。
總結一下,在這種地方你一定要考慮使用訪問者模式:業務規則要求遍歷多個不同的對象。這本書也是訪問者模式出發點,迭代器模式只能訪問同類或同接口的數據,而訪問者模式是對迭代器模式的擴充,可以遍歷不同的對象,然後執行不同的操作,也就是針對訪問的對象不同,執行不同操作。訪問者模式還有一個用途,就是衝動攔截器角色。
1.4最佳實踐
訪問者模式是一種集中規整模式,特別適用於大規模重構的項目,在這一個階段需求已經非常清晰,原系統的功能點也已經明確,通過訪問者模式可以很容易把一些功能進行梳理,達到最終目的——功能集中化,如一個統一的報表運算、UI展現等,我們還可以與其它模式混編建立一套自己的過濾器或者攔截器。
其它設計模式內容戳這裏。