訪問者模式看起來是一個非常機(jī)智的模式,它做到了將類的架構(gòu)設(shè)計和邏輯代碼解耦的目標(biāo)。為了要完成對訪問者模式的解釋,我們要明確這兩個概念:架構(gòu)設(shè)計和邏輯代碼。
架構(gòu)設(shè)計
一般來說我們在設(shè)計Java類層次結(jié)構(gòu)的時候,會用到類的繼承和擴(kuò)展。這樣一來會產(chǎn)生出一個繼承層次,也就是我們的類架構(gòu)設(shè)計。我們在后續(xù)的版本更新中,為了滿足新的需求,也很可能會發(fā)生架構(gòu)變更的情況。
邏輯代碼
針對上述的架構(gòu)設(shè)計,引申出與之相關(guān)的業(yè)務(wù)邏輯和操作。需要說明的是,這些業(yè)務(wù)操作可能是在架構(gòu)設(shè)計的類中實現(xiàn)的,也可能是在架構(gòu)設(shè)計之外的其他類或其他方法中實現(xiàn)的。
那么為了讓架構(gòu)設(shè)計和邏輯代碼能夠結(jié)構(gòu),我們就有了訪問者模式:
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 operates.
訪問者模式代表了一種能夠操作在架構(gòu)設(shè)計中的類的方式,它能夠讓你在不改動類的前提下定義一個新的操作。
還是和之前一樣,我們來看一下它的類圖:
看起來比較龐大比較唬人,但是我們可以將整個圖分為上下兩部分:Visitor和Element。
Element
元素,其實就是在整個架構(gòu)設(shè)計中的一個個類結(jié)點(diǎn),它有著自己的業(yè)務(wù)含義和業(yè)務(wù)操作。
Visitor
訪問者,為了給Element增加新的操作而新建的類,保存了我們想加在Element身上的附加操作。
根據(jù)以上的分析,我們可以得出Visitor和Element交互的目的,就是使得Visitor定義的方法能夠運(yùn)行在Element上。為了達(dá)到這個效果我們需要進(jìn)行的就是Visitor和Element的交互,使得某些方法能夠被對方訪問到。
我們現(xiàn)在來看一下,這兩個角色之間實際上是如何進(jìn)行交互的。首先我們來看一下Visitor應(yīng)該如何進(jìn)行定義和實現(xiàn):
public interface Visitor{
void visit(ConcreteElementA a);
void visit(ConcreteElementB b);
}
public class ConcreteVisitor implements Visitor{
public void visit(ConcreteElementA a){
//do something about a
}
public void visit(ConcreteElementB b){
//do something about b
}
}
從代碼我們可以看出,其實是在Visitor的方法中,我們將Element的實例傳入了方法,在方法中具體操作這個實例。而Element需要如何與Visitor進(jìn)行交互呢?
public interface Element{
void accept(Visitor v);
}
public class ConcreteElementA implements Element{
public void accept(Visitor v){
v.visit(this);
}
}
public class ConcreteElementB implements Element{
public void accept(Visitor v){
v.visit(this);
}
}
代碼表明其實也是作為參數(shù)傳入的,而在方法中我們調(diào)用了接口方法visit(),并將自己(this)傳給了方法,這樣得以讓visitor訪問到了Element,以便在visitor內(nèi)部進(jìn)行其他操作。這樣一來,為Element新增的方法被放入了一個外部的類中,并且能夠靈活增加其他代碼,而基本上不需要修改Element的相關(guān)代碼。我們需要做的,就是在Client堆Element進(jìn)行使用的時候,傳入對應(yīng)的Visitor類型。