在類的內部結構不變的情況下,不同的訪問者訪問這個對象,都會呈現出不同的效果。
訪問者模式有以下角色
- 元素類:是一個抽象類或者接口,裏面會定義一個接收(accept)訪問者的抽象方法,使得每一個元素能被訪問者訪問。
- 具體元素:繼承或實現元素類,實現接收方法。
- 訪問者:一般是一個抽象類,裏面涵括了可以訪問每個具體元素的方法,使得訪問者可以訪問每個具體元素(一般有幾個具體元素就會有幾個這個樣的方法,這些方法的方法名相同參數不同,參數都是具體元素,所以一般來説具體元素的種類應該是比較固定的)。
- 具體訪問者:訪問者的具體實現
例如我們定義景區是一個元素類,西湖、長城是一個具體的元素類,遊客就是訪問者的抽象,那麼遊客A、遊客B就是具體的訪問者。
景區類中有一個接收方法參數是遊客類型,由於多態特性所以我們可以傳入遊客A、遊客B等子類。
遊客類中會有多個訪問方法,它們的方法名相同,參數不同,分別為西湖、長城等具體元素類
具體景區-西湖會實現父類中的接收抽象方法,然後方法中調用傳入的遊客對象的訪問方法,參數設為this也就是西湖類的對象,這就相當於調用了遊客類中的參數為西湖的訪問方法。
具體類圖如下
下面使用一個類似的樣例,國家領導人進行國際訪問來進行代碼實現
元素類 - 國家
public abstract class Country {
private String capital;
public Country(String capital) {
this.capital = capital;
}
public String getCapital() {
return capital;
}
abstract void accept(NationalLeader leader);
}
具體元素類 - 美國、日本
public class America extends Country {
public America(String capital) {
super(capital);
}
@Override
public void accept(NationalLeader leader) {
leader.visit(this);
}
}
public class Japan extends Country {
public Japan(String capital) {
super(capital);
}
@Override
public void accept(NationalLeader leader) {
leader.visit(this);
}
}
訪問者 - 國家領導人
public interface NationalLeader {
void visit(America america);
void visit(Japan japan);
//這裏面還可以訪問 中國、巴西、法國、英國.....被訪問的通常是固定不變的,而訪問者可以是任何人,相對來説更加靈活
}
具體訪問者 - 普京
public class Putin implements NationalLeader{
@Override
public void visit(America america) {
System.out.println("普京抵達美國首都"+america.getCapital());
}
@Override
public void visit(Japan japan) {
System.out.println("普京抵達日本首都"+japan.getCapital());
}
}
測試
public class VisitorTest {
@Test
public void test(){
Country america = new America("華盛頓");
america.accept(new Putin());
Country japan = new Japan("東京");
japan.accept(new Putin());
}
}
=====結果=====
普京抵達美國首都華盛頓
普京抵達日本首都東京
優點:
- 使得數據結構(元素類)和作用於結構上的操作(訪問者)解耦,使得操作集合可以獨立變化。
- 便於靈活添加操作(訪問者)。
- 將對各個元素的一組操作集中在一個訪問者類當中。
- 可以跨越類層次結構,訪問不同層次的元素類,做出相應的操作。
缺點:
- 增加新的元素會非常困難。
- 實現起來比較複雜,會增加系統的複雜性。
- 破壞封裝,如果將訪問行為放在各個元素中,則可以不暴露元素的內部結構和狀態,但使用訪問者模式的時候,為了讓訪問者能獲取到所關心的信息,元素類不得不暴露出一些內部的狀態和結構,就像收入和支出類必須提供訪問金額和單子的項目的方法一樣。
適用性:
- 數據結構穩定,作用於數據結構的操作經常變化的時候。
- 當一個數據結構中,一些元素類需要負責與其不相關的操作的時候,為了將這些操作分離出去,以減少這些元素類的職責時,可以使用訪問者模式。
- 有時在對數據結構上的元素進行操作的時候,需要區分具體的類型,這時使用訪問者模式可以針對不同的類型,在訪問者類中定義不同的操作,從而去除掉類型判斷。