訪問者模式

定義

  • 表示做用於某對象結構中的各元素的操做。它可使你在不改變各元素的類的前提下定義做用於這些元素的新操做 [引用大話設計模式概念]
  • 維護了開放-封閉原則(拓展開放,更改封閉)

應用場景

適用於數據結構相對穩定的系統
例:1. apt(註解處理工具)經過訪問者模式解析註解(參照Think in Java P632);2.大話設計模式中,男人和女人對待不一樣狀態作出不一樣相應的例子設計模式

優缺點

  • 優勢
    • 處理與數據結構分離(解耦合)
      ps: 這裏的數據結構舉例:人類中只有男人女人,男人和女人就是人類的數據結構
    • 使用雙分派
      增長新的操做時,只須要增長新的訪問者,無需改動其餘代碼(可參照下例代碼)
      1. 客戶端調用時,調用元素的accept方法,具體訪問者做爲參數
      2. accept方法中,調用訪問者的方法,並將本身(具體元素)做爲參數傳入
    • 增長新的訪問者(新的操做)很容易,
  • 缺點
    • 增長新的數據結構會很困難
      例如,人類中增長一個種類,那麼全部的訪問者都要增長一個對此種類的處理

類圖

 
訪問者模式類圖.jpg
  • 類圖中有四個重要元素:VisitorConcreteVisitorElementConcreteElement
    1. 抽象訪問者(Visitor):爲每一個Element的實現聲明一個Visit(訪問)操做,可爲接口或抽象類
    2. 具體訪問者(ConcreteVisitor):實現Visitor的操做
      實現具體的訪問行爲
    3. 抽象元素(Element):具體數據結構的抽象
      聲明一個accept(接受操做),接受一個訪問者對象做爲參數
    4. 具體元素(ConcreteVisitor):實現了抽象元素的accept
      通常會在accept方法的實現中,直接作一次分派

男人與女人的例子

  • 引用大話設計模式中男人和女人的例子
  • 男人和女人面對不一樣的狀態,有不一樣的反應
    1. 人類(Element),抽象訪問者,擁有一個accept(接受狀態)的方法,會面臨多種狀態:成功、失敗、戀愛、結婚
    2. 男人、女人(ConcreteVisitor一、ConcreteVisitor2),實現本身的accept(接受狀態時的反應)。面對狀態,都會作出本身的反應
    3. 狀態(Visitor),定義兩個方法:男人對狀態的反應、女人對狀態的反應
    4. 具體狀態(戀愛、失敗等)(ConcreteVisitor一、ConcreteVisitor二、ConcreteVisitor三、ConcreteVisitor4...)
訪問者模式代碼:
  • 抽象元素:人類
/**
 * Element(抽象元素):人類
 */
public interface Person {
    /**
     * 接受狀態
     * @param action
     */
    String accept(Action action);
}

 

  • 抽象訪問者:
/**
 * Action(抽象訪問者):狀態
 */
public interface Action {
    /**
     * 獲取男人的反應
     * @param person
     * @return
     */
    String GetManConclusion(Man person);
    /**
     * 獲取女人反應
     * @param person
     * @return
     */
    String GetManConclusion(Woman person);
}

 

  • 具體元素:男人、女人
    男人
/**
 * ConcreteElement(抽象訪問者): 男人
 */
public class Man implements Person {
    @Override
    public String accept(Action action) {
        // 第二次分派,調用action(訪問者)的方法,把本身(元素自己)做爲參數傳入
        return action.GetManConclusion(this);
    }
}

 

女人數據結構

/**
 * ConcreteElement(抽象訪問者): 女人
 */
public class Woman implements Person {
    @Override
    public String accept(Action action) {
        // 第二次分派,調用action(訪問者)的方法,把本身(元素自己)做爲參數傳入
        return action.GetManConclusion(this);
    }
}

 

  • 具體狀態:成功、失敗、戀愛等等
    成功
/**
 * ConcreteVisitor(具體訪問者): 成功狀態的響應
 */
public class Success implements Action {
    @Override
    public String GetManConclusion(Man person) {
        return "男人成功時,背後總有一個偉大的女人";
    }

    @Override
    public String GetManConclusion(Woman person) {
        return "女人成功時,背後大多有一個不成功的男人";
    }
}

 

失敗ide

/**
 * ConcreteVisitor(具體訪問者): 失敗狀態的響應
 */
public class Failure implements Action {
    @Override
    public String GetManConclusion(Man person) {
        return "男人失敗時,悶頭喝酒,誰也不用勸";
    }

    @Override
    public String GetManConclusion(Woman person) {
        return "女人失敗時,眼淚汪汪,誰也勸不了";
    }
}

 

戀愛工具

/**
 * ConcreteVisitor(具體訪問者): 戀愛狀態的響應
 */
public class Love implements Action{
    @Override
    public String GetManConclusion(Man person) {
        return "男人戀愛是,凡事不懂也要裝懂";
    }

    @Override
    public String GetManConclusion(Woman person) {
        return "女人戀愛時,遇事懂也裝做不懂";
    }
}

 

  • 枚舉元素
/**
 * 用來枚舉元素,包含多個元素
 */
public class ObjectStructure {
    private List<Person> elements = new ArrayList<>();

    public void add(Person person) {
        if (null != person) {
            this.elements.add(person);
        }
    }

    public void del(Person person) {
        if (null != person) {
            this.elements.remove(person);
        }
    }

    /**
     * 獲取並展現元素對指定狀態的響應
     * @param action 指定狀態
     */
    public void accept(Action action) {
        if (null == this.elements || 0 >= this.elements.size()) {
            return;
        }
        this.elements.forEach(element -> {
            // 第一次分派,調用元素的接受狀態方法,將action(訪問者)做爲參入
            String result = element.accept(action);
            System.out.println("person: " + element.getClass().getName() + "action: " + action.getClass().getName() +
                    "conclusion: " + result);
        });
    }
}
相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息