訪問者模式(Visitor)

一、概念

訪問者模式封裝一些做用於某種數據結構中的各元素的操做,它能夠在不改變這個數據結構的前提下定義做用於這些元素的新的操做,屬於行爲型模式一種。 bash

圖片

二、模式結構

  • Visitor(抽象訪問者):抽象訪問者爲對象結構中每個具體元素類ConcreteElement聲明一個訪問操做,從這個操做的名稱或參數類型能夠清楚知道須要訪問的具體元素的類型,具體訪問者則須要實現這些操做方法,定義對這些元素的訪問操做。
  • ConcreteVisitor(具體訪問者):具體訪問者實現了抽象訪問者聲明的方法,每個操做做用於訪問對象結構中一種類型的元素。
  • Element(抽象元素):通常是一個抽象類或接口,定義一個Accept方法,該方法一般以一個抽象訪問者做爲參數。
  • ConcreteElement(具體元素):具體元素實現了Accept方法,在Accept方法中調用訪問者的訪問方法以便完成一個元素的操做。
  • ObjectStructure(對象結構):對象結構是一個元素的集合,用於存放元素對象,且提供便利其內部元素的方法。

三、使用場景

  • 一個對象結構包含不少類操做,它們有不一樣的接口,而你想對這些對象實施一些依賴於其具體類的操做。
  • 須要對一個對象結構中的對象進行不少不一樣的而且不相關的操做,而你想避免讓這些操做污染這些對象的類。
  • 定義對象結構的類不多改變,但常常須要在此結構上定義新的操做。

四、優缺點

優勢:數據結構

  • 將有關元素對象的訪問行爲集中到一個訪問者對象中,而不是分散在一個個的元素類中,類的職責更加清晰,符合單一職責原則
  • 優秀的擴展性,元素類能夠經過接受不一樣的訪問者來實現對不一樣操做的擴展
  • 靈活性高,可以使得用戶在不修改現有類的層次結構下,定義該類層次結構的操做

缺點:ide

  • 增長新的元素類很困難,須要在每個訪問者類中增長相應訪問操做代碼,這違背了開閉原則
  • 元素對象有時候必須暴露一些本身的內部操做和狀態,不然沒法供訪問者訪問,這破壞了元素的封裝性

五、實例

定義Visitor(抽象訪問者)ui

public interface Visitor {
    float visit(FoodElement food);

    float visit(FruitElement fruit);
}
複製代碼

定義Element(抽象元素)this

public interface Element {
    float accept(Visitor visitor);
}
複製代碼

定義具體元素FruitElementspa

public class FoodElement implements Element {

    private float price;
    private int num;

    public FoodElement(int num, float price) {
        this.num = num;
        this.price = price;
    }

    public float getPrice() {
        return price;
    }

    public int getNum() {
        return num;
    }

    @Override
    public float accept(Visitor visitor) {
        return visitor.visit(this);
    }
}
複製代碼

定義具體元素FruitElementcode

public class FruitElement implements Element {

    private float price;
    private int num;

    public FruitElement(int num, float price) {
        this.num = num;
        this.price = price;
    }

    public float getPrice() {
        return price;
    }

    public int getNum() {
        return num;
    }

    @Override
    public float accept(Visitor visitor) {
        return visitor.visit(this);
    }
}
複製代碼

定義具體的ConcreteVisitorcdn

public class ConcreteVisitor implements Visitor {

    @Override
    public float visit(FoodElement food) {
        return food.getNum() * food.getPrice();
    }

    @Override
    public float visit(FruitElement fruit) {
        return fruit.getNum() * fruit.getPrice();
    }
}
複製代碼

定義對象結構ObjectStructure對象

public class ObjectStructure {
    private List<Element> list = new ArrayList<>();

    /**
     * 訪問者訪問元素的入口
     *
     * @param visitor 訪問者
     */
    public void accept(Visitor visitor) {
        for (int i = 0; i < list.size(); i++) {
            Element element = list.get(i);
            element.accept(visitor);
        }
    }

    /**
     * 把元素加入到集合
     *
     * @param element 待添加的元素
     */
    public void addElement(Element element) {
        list.add(element);
    }

    /**
     * 把元素從集合中移除
     *
     * @param element 要移除的元素
     */
    public void removeElement(Element element) {
        list.remove(element);
    }
}
複製代碼

客戶端使用blog

ObjectStructure objectStructure = new ObjectStructure();
objectStructure.addElement(new FoodElement(10, 2));
objectStructure.addElement(new FruitElement(10, 2));
objectStructure.accept(new ConcreteVisitor());
複製代碼
相關文章
相關標籤/搜索