設計模式系列:一文帶你領略“訪問者模式”的魅力
訪問者模式相對來說比較抽象和難以理解,可能單純地通過文字、類圖、案例代碼大家還是不太容易理解該模式,不過希望大家不要急躁,可以靜下心來用心的體會該設計模式的魅力。相信你一定會有所收獲。
基本介紹
訪問者模式的基本概念:封裝一些作用于某種數據結構中元素上的操作。其有一個重要的特征是可以在不改變數據結構的前提下定義一些新的操作。
簡單來說訪問者模式主要的作用就是將“數據結構”和“數據操作”進行分離,解決這兩者之間耦合性的問題。
訪問者模式的基本執行原理就是在被訪問的類里添加一個接口,用于接待訪問者。
一般數情況下,當我們需要對一個數據結構中的元素進行很多不同的操作,并且這些操作彼此之間并沒有關聯,同時我們還想做到避免因為這些操作而“污染”了這些元素時,就可考慮使用訪問者模式。
訪問者模式UML類圖

類圖講解
Visitor:抽象訪問角色;通常情況下該數據結構中有幾個元素就會對應的在該類中為每一個元素提供一個訪問操作(方法)。
ConcreteVisitor:具體訪問者角色;繼承了Visitor并實現了其中定義的所以方法。
Element:抽象元素角色;該類會定義一個accept(接收)方法,用于接收訪問者。
ConcreteElement:具體元素角色;繼承了Element并實現了其中定義的accept方法。
ObjectStruture:該類定義了數據結構(對象結構),管理了所有元素,并且可以枚舉它的元素(也就是遍歷)。
案例講解
案例:開發一個員工審批功能,具體為不同角色的員工可以進行“同意”和“不同意”的審批。
抽象員工類 => 對應Element(抽象元素角色)
- public abstract class Workers {
- // 提供一個讓訪問者訪問的方法
- public abstract void accept(Action action);
- }
具體員工類
- /**
- * 經理
- */
- public class Manager extends Workers {
- /**
- * 這里用到了雙分派。
- * 第一次分派:在客戶端中將具體的Action作為參數傳遞到Manager中。
- * 第二次分派:Manager類調用Action中的具體方法,并將自己作為參數傳入。
- */
- @Override
- public void accept(Action action) {
- action.managerVerify(this);
- }
- }
- /**
- * 組長
- */
- public class GroupLeader extends Workers {
- @Override
- public void accept(Action action) {
- action.groupLeaderVerify(this);
- }
- }
抽象行為類 => 對應Visitor(抽象訪問角色)
- public abstract class Action {
- // 經理進行審批
- public abstract void managerVerify(Manager manager);
- // 組長進行審批
- public abstract void groupLeaderVerify(GroupLeader groupLeader);
- }
具體行為類
- /**
- * 同意
- */
- public class Agree extends Action {
- @Override
- public void managerVerify(Manager manager) {
- System.out.println("經理的審核結果為同意!");
- }
- @Override
- public void groupLeaderVerify(GroupLeader groupLeader) {
- System.out.println("組長的審核結果為同意!");
- }
- }
- /**
- * 不同意
- */
- public class Disagree extends Action {
- @Override
- public void managerVerify(Manager manager) {
- System.out.println("經理的審核結果為不同意!");
- }
- @Override
- public void groupLeaderVerify(GroupLeader groupLeader) {
- System.out.println("組長的審核結果為不同意!");
- }
- }
ObjectStructure類
- public class ObjectStructure {
- // 維護了一個集合
- private List<Workers> peoples = new ArrayList<>();
- // 增加
- public void attach(Workers workers) {
- peoples.add(workers);
- }
- // 移除
- public void detach(Workers workers) {
- peoples.remove(workers);
- }
- // 顯示測評情況
- public void display(Action action) {
- for (Workers people : peoples) {
- people.accept(action);
- }
- }
- }
客戶端測試類
- public class Client {
- public static void main(String[] args) {
- ObjectStructure objectStructure = new ObjectStructure();
- // 添加人
- objectStructure.attach(new Manager());
- objectStructure.attach(new GroupLeader());
- // 同意
- Agree agree = new Agree();
- objectStructure.display(agree);
- }
- }
執行結果

總結
優點:
1、訪問者模式符合單一職責原則。
2、可以讓數據結構和數據操作之間解耦。
3、避免了因為操作元素而對其造成污染的問題。
4、讓程序具有擴展性的情況下還大大增加了靈活性。
缺點:
1、因為具體的元素對訪問者公布了實現細節,所以訪問者模式是違背了迪米特法則的。這樣做會導致元素變化比較困難。
2、因為訪問者依賴的是具體的元素而不是其抽象父類,所有該模式還違背了依賴倒轉原則。
總結 :訪問者模式適用于數據結構相對穩定并且功能需求還經常變化的系統。