訪問者模式是23種設計模式中最復雜的一個,使用頻率并不高,一般不需要用,如果你一旦需要使用,那就是真的需要了。
它是一種將數據操作和數據結構分離的設計模式。
定義
封裝一些作用于某種數據結構中的各元素操作,它可以在不改變這個數據結構的前提下定義作用于這些元素的新的操作。
使用場景
1.對象結構比較穩定,但經常需要再次對象結構上定義新的操作。
2.需要對一個對象結構中的對象進行很多不同的并且不相關的操作,而需要避免這些操作“污染”這些對象的類,也不希望在增加新操作時修改這些類。
來看一個實現
企業業績考核,有工程師和經理兩種職工,老板有CEO和CTO,CTO只關心工程師的代碼數量、經理的產品數量。CEO關心工程師和經理的KPI。
于是我們定一個staff員工基類,有一個抽象方法accept(Visitor visitor),他有兩個子類Engineer和Mnager,他們實現了accept(Visitor visitor)方法,并且在accept方法中調用visitor.visit(this);
而Visitor類中的visit方法有兩個重載一個是visit(Engineer)另一個是visit(Manager),而Visitor類兩個子類CTO和CEO兩個類在實現這兩個visit方法的時候去根據需求來訪問不同的數據就行了。
最后有一個中的報表類,類里面用例如List存儲了所有員工的資料,然后有一個showReport(Visitor visitor)方法,方法里面遍歷所有員工accpet并傳入visitor。
每一個對象的accept(Visitor)調用了visitor.visit(this)方法,visitor中又根據傳過來的this判斷是哪個對象去獲取需要的數據。
這就是一個訪問者模式的簡單實現,其實也還是不難的。
Android源碼中的訪問者模式
編譯時注解依賴于APT(Annotation Processing Tools)實現,在編譯器會自己生成相關的java類。
注解可以指定作用于哪種元素上, ?比如:
PackageElement,包元素
TypeElement,類型元素
ExecutableElement,可執行元素
VariableElement,變量元素
TypeParameterElement,類型參數元素
Element基類里面有一個accept(ElementVisitor<R,p> v,P p)方法
ElementVisitor里面又根據不同的元素類型重載很很多visit方法。
比如類型元素訪問者 里面是visitType(TypeElement e,P p)方法,然后里面做了這種類型元素需要的操作。
顯然這就是一個訪問者模式。
優點:
1.角色職責分離,符合單一職責原則。
2.具有優秀的擴展性。
3.使得數據結構和作用于結構上的操作解耦,使得操作集合可以獨立變化。
4.靈活性。
缺點:
1.具體元素對訪問者公布細節,違反了迪米特原則
2.具體元素變更時,修改成本大
3.違反了依賴倒置原則,為了區別對待而依賴了具體類,而不是依賴抽象。