訪問者模式
一、定義
封裝一些作用於某種數據結構中的各元素的操作,它可以在不改變數據結構的前提下定義作用於這些元素的新的操作
通用類圖
Visitor是抽象訪問者,聲明訪問者可以訪問那些元素,在程序中visit方法的參數定義那些對象是可以被訪問的;ConcreteVisitor是具體訪問者,它定義訪問者訪問到一個類後要做什麼事情;Element是抽象元素,生命接收哪一些類訪問者訪問,通過accept方法中的參數定義;ConcreteElement是具體元素,實現accept方法,通常是visitor.visit(this);ObjectStruture是結構對象,是元素產生着,一般容納在多個不同類、不同接口的容器。在項目
中,一般很少抽象出這個角色
訪問者模式通用源碼
-
抽象元素
public abstract class Element { //定義業務邏輯 public abstract void doSomething(); //允許誰來訪問 public abstract void accept(IVisitor visitor); }
-
具體元素
public class ConcreteElement1 extends Element{ //完善業務邏輯 public void doSomething(){ //業務處理 } //允許那個訪問者訪問 public void accept(IVisitor visitor){ visitor.visit(this); } } public class ConcreteElement2 extends Element{ //完善業務邏輯 public void doSomething(){ //業務處理 } //允許那個訪問者訪問 public void accept(IVisitor visitor){ visitor.visit(this); } }
-
抽象訪問者
public interface IVisitor { //可以訪問哪些對象 public void visit(ConcreteElement1 el1); public void visit(ConcreteElement2 el2); }
-
具體訪問者
public class Visitor implements IVisitor { //訪問el1元素 public void visit(ConcreteElement1 el1) { el1.doSomething(); } //訪問el2元素 public void visit(ConcreteElement2 el2) { el2.doSomething(); } }
-
結構對象
public class ObjectStruture { //對象生成器,這裏通過一個工廠方法模式模擬 public static Element createElement(){ Random rand = new Random(); if(rand.nextInt(100) > 50){ return new ConcreteElement1(); }else{ return new ConcreteElement2(); } } }
-
場景類
public class Client {
public static void main(String[] args) {
for(int i=0;i<10;i++){
//獲得元素對象
Element el = ObjectStruture.createElement();
//接受訪問者訪問
el.accept(new Visitor());
}
}
}
二、訪問者模式的優點
-
符合單一職責原則
具體元素角色負責數據的加載,Visitor類負責報表的展現,兩個不同的職責分離開,各自演繹變化。
-
優秀的擴展性
由於職責分開,繼續增加對數據的操作是非常快捷的。
-
靈活度非常高
三、訪問者模式的缺點
-
具體元素(ConcreteElement)對訪問者公佈細節
訪問者要訪問一個類就必須瞭解其內部細節,不符合迪米特法則
-
具體元素變更比較困難
具體元素的增加、刪除、修改需要對修改所有的Visitor
-
違背了依賴倒置原則
訪問者依賴的是具體元素,而不是抽象元素,破壞了依賴倒置原則,擴展比較難
四、訪問則模式的的使用場景
-
一個對象結構包含很多類對象,他們有不同的接口,而你想對這些對象實施一些依賴於其具體類的操作(對不同類型的對象執行不同的操作),也就會說用迭代器模式已經不能勝任的場景。
-
需要對一個對象結構中的對象進行很多不同並且不相關的操作,而你想避免讓這些操作”污染“這些對象的類
即 業務規則要求遍歷多個不同的對象時。迭代器模式只能訪問同類或同接口的數據,而訪問者模式是對迭代器模式的擴充,可以遍歷不同的對象,然後執行不同的操作,也就是針對訪問的對象不同,執行不同的操作