訪問者模式(Visitor Pattern)的目的是封裝一些於某種數據結構元素之上的操作,一旦這些元素需要修改,接受這個操作的數據結構則可以保持不變。 定義: 封裝一些作用於某種數據結構中的各元素的操作,它可以在不改變數據結構的前提下定義於作用這些元素的新的操作。 訪問者模式的類圖如下。 訪問者模式 ...
訪問者模式(Visitor Pattern)的目的是封裝一些於某種數據結構元素之上的操作,一旦這些元素需要修改,接受這個操作的數據結構則可以保持不變。
定義:
- 封裝一些作用於某種數據結構中的各元素的操作,它可以在不改變數據結構的前提下定義於作用這些元素的新的操作。
訪問者模式的類圖如下。
訪問者模式涉及以下5個角色。
- 抽象訪問者(Visitor)角色:該角色聲明一個或多個訪問操作,定義訪問者可以訪問哪些元素。
- 具體訪問者(Concrete Visitor)角色:該角色實現抽象訪問者角色中的各個訪問操作。
- 抽象元素(Element)角色:聲明一個接受操作,接受一個訪問者對象。
- 具體元素(Concrete Element)角色:實現抽象元素中的接受操作。
- 結構對象(Object Structure)角色:該角色有以下責任,可以遍歷結構中的所有元素;如果需要,提供一個高層次的介面讓訪問者對象可以訪問每一個元素,也可以設計一個複合對象或者一個集合,如List或Set.
Element.java
// 抽象元素角色 public abstract class Element { // 接受操作 public abstract void accept(Visitor vi); }
ConcreteElement1.java
// 具體元素1 public class ConcreteElement1 extends Element { @Override public void accept(Visitor vi) { vi.visit(this); } // 業務邏輯方法 public void operation() { System.out.println("訪問元素1"); } }
ConcreteElement2.java
//具體元素2 public class ConcreteElement2 extends Element { @Override public void accept(Visitor vi) { vi.visit(this); } // 業務邏輯方法 public void operation() { System.out.println("訪問元素2"); } }
Visitor.java
// 抽象訪問者 public interface Visitor { // 可以訪問哪些對象 public void visit(ConcreteElement1 el1); public void visit(ConcreteElement2 el2); }
ConcreteVisitor.java
// 具體訪問者角色 public class ConcreteVisitor implements Visitor { // 訪問元素1 @Override public void visit(ConcreteElement1 el1) { el1.operation(); } // 訪問元素2 @Override public void visit(ConcreteElement2 el2) { el2.operation(); } }
ObjectStructure.java
// 結構對象角色 public class ObjectStructure { private Vector<Element> elements; // 構造函數 public ObjectStructure() { this.elements = new Vector<Element>(); } // 執行訪問操作 public void action(Visitor vi) { for (Element e : elements) { e.accept(vi); } } // 添加新元素 public void add(Element e) { elements.add(e); } // 元素生成器,這裡通過一個工廠方法進行模擬 public void createElements() { Random rand = new Random(); for (int i = 0; i < 10; i++) { if (rand.nextInt(100) > 50) { // 添加元素1 this.add(new ConcreteElement1()); } else { // 添加元素2 this.add(new ConcreteElement2()); } } } }
Client.java
public class Client { public static void main(String[] args) { // 創建一個結構對象 ObjectStructure os = new ObjectStructure(); // 生成元素 os.createElements(); // 創建一個訪問者對象 Visitor vi = new ConcreteVisitor(); // 訪問者對結構進行訪問(執行訪問) os.action(vi); } }
運行結果如下所示。
訪問元素1 訪問元素1 訪問元素1 訪問元素2 訪問元素2 訪問元素2 訪問元素1 訪問元素1 訪問元素1 訪問元素2
優點:
- 元素(Element)角色負責數據載入,Visitor負責數據展現。
- 增加新的操作,直接在Visitor中增加一個方法。
- 集中行為,系統容易維護。
缺點:
- 具體元素對訪問者公佈細節,破壞封裝性;
- 具體元素變更變更變得困難。具體元素的增加和修改等,需要具體訪問者修改。
- 違背了依賴倒置原則。訪問者依賴的是具體元素,而不是抽象元素,拋棄了對介面的依賴,而直接依賴實現類,擴展比較困難。
應用場景:
- 一個對象結構包含很多類對象,它們有不同的介面。
- 需要對一個對象結構中的對象進行很多不同並且不相關的操作,避免操作污染類。
- 業務規則要求遍歷多個不同的對象,這本身也是訪問模式的出發點,迭代器模式只能訪問同類或同介面的數據,而訪問者模式是對迭代器模式的擴充,可以遍歷不同的對象,執行不同的操作。
摘自:
青島東合信息技術有限公司 . 設計模式(Java版) . 電子工業出版社,2012,161-166.