訪問者(Visitor)模式:封裝一些作用于某種數據結構中的各元素的操作,它可以在不改變這個數據結構的前提下定義作用于這些元素的新的操作。訪問者模式的結構圖如下:
通過上圖可以看到他有如下角色:
抽象訪問者(Visitor)角色:定義接口,聲明一個或多個訪問操作。
具體訪問者(ConcreteVisitor)角色:實現抽象訪問者所聲明的接口,也就是抽象訪問者所聲明的各個訪問操作。
抽象元素(Visitable)角色:聲明一個接受操作,接受一個訪問者對象作為一個參數。
具體元素結點(ConcreteElement)角色:實現抽象結點所規定的接受操作。
數據結構對象(ObjectStructure)角色:可以遍歷結構中的所有元素,提供一個接口讓訪問者對象都可以訪問每一個元素。
模擬代碼如下:
1
2
3
4
5
|
interface Visitor { void visit(Gladiolus g); void visit(Chrysanthemum c); } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// concrete visitor 名稱訪問 class StringVisitor implements Visitor { String s; public String toString() { return s; } public void visit(Gladiolus g) { s = "Gladiolus" ; } public void visit(Chrysanthemum c) { s = "Chrysanthemum" ; } } |
1
2
3
4
5
6
7
8
9
10
11
|
// concrete visitor 蜜蜂訪問 class BeeVisitor implements Visitor { public void visit(Gladiolus g) { System.out.println( "蜜蜂 來 訪問 Gladiolus" ); } public void visit(Chrysanthemum c) { System.out.println( "蜜蜂 來 訪問 Chrysanthemum" ); } } |
1
2
3
|
interface Flower { void accept(Visitor v); } |
1
2
3
4
5
6
7
8
|
/* * concrete element 菊花 */ class Chrysanthemum implements Flower { public void accept(Visitor v) { v.visit( this ); } } |
1
2
3
4
5
6
|
// concrete element 劍蘭 class Gladiolus implements Flower { public void accept(Visitor v) { v.visit( this ); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//這是Flower一個對象生成器 class FlowerGenerator { private static Random rand = new Random(); public static Flower newFlower() { switch (rand.nextInt( 2 )) { default : case 0 : return new Gladiolus(); case 1 : return new Chrysanthemum(); } } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public class Test { /* * 首先在客戶端先獲得一個具體的訪問者角色 遍歷對象結構 對每一個元素調用accept方法,將具體訪問者角色傳入 這樣就完成了整個過程 */ public static void main(String args[]) { List<Flower> flowers = new ArrayList<Flower>(); for (int i = 0; i < 10; i++) flowers.add(FlowerGenerator.newFlower()); Visitor visitor = new StringVisitor(); Iterator<Flower> iterator = flowers.iterator(); while (iterator.hasNext()) { iterator.next().accept(visitor); System.out.println(visitor); } System.out.println("---------------"); /* * 一個新的訪問行為 :BeeVisitor 蜜蜂訪問 */ Visitor visitor2 = new BeeVisitor(); for (Flower flower : flowers) { flower.accept(visitor2); } } } |
結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
Gladiolus Chrysanthemum Chrysanthemum Gladiolus Chrysanthemum Chrysanthemum Chrysanthemum Chrysanthemum Gladiolus Gladiolus --------------- 蜜蜂 來 訪問 Gladiolus 蜜蜂 來 訪問 Chrysanthemum 蜜蜂 來 訪問 Chrysanthemum 蜜蜂 來 訪問 Gladiolus 蜜蜂 來 訪問 Chrysanthemum 蜜蜂 來 訪問 Chrysanthemum 蜜蜂 來 訪問 Chrysanthemum 蜜蜂 來 訪問 Chrysanthemum 蜜蜂 來 訪問 Gladiolus 蜜蜂 來 訪問 Gladiolus |
有以下情形可以考慮使用訪問者模式:
1、一個對象結構包含很多類對象,它們有不同的接口,而你想對這些對象實施一些依賴于其具體類的操作。
2、需要對一個對象結構中的對象進行很多不同的并且不相關的操作,而你想避免讓這些操作“污染”這些對象的類。Visitor使得你可以將相關的操作集中起來定義在一個類中。
3、當該對象結構被很多應用共享時,用Visitor模式讓每個應用僅包含需要用到的操作。
4、 定義對象結構的類很少改變,但經常需要在此結構上定義新的操作。改變對象結構類需要重定義對所有訪問者的接口,這可能需要很大的代價。如果對象結構類經常改變,那么可能還是在這些類中定義這些操作較好。
這些個人看來都是建議,項目中還要具體問題具體分析了。