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