設計模式-行爲型之訪問者(Visitor)模式

定義

  • 將數據結構和對數據結構的操作分離。

使用場景

  • 穩定的數據結構和易變的操作耦合問題。
  • 需要對一個對象結構中的對象進行很多不同的並且不相關的操作,而需要避免這些操作“污染”這些對象的類,也不希望在增加新操作時修改這些類。

UML圖

代碼實現

代碼來源:https://www.jianshu.com/p/1f1049d0a0f4
年底,CEO和CTO開始評定員工一年的工作績效,員工分爲工程師和經理,CTO關注工程師的代碼量、經理的新產品數量;CEO關注的是工程師的KPI和經理的KPI以及新產品數量。
由於CEO和CTO對於不同員工的關注點是不一樣的,這就需要對不同員工類型進行不同的處理。訪問者模式此時可以派上用場了。

// 員工基類
public abstract class Staff {

    public String name;
    public int kpi;// 員工KPI

    public Staff(String name) {
        this.name = name;
        kpi = new Random().nextInt(10);
    }
    // 核心方法,接受Visitor的訪問
    public abstract void accept(Visitor visitor);
}
// 工程師
public class Engineer extends Staff {

    public Engineer(String name) {
        super(name);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    // 工程師一年的代碼數量
    public int getCodeLines() {
        return new Random().nextInt(10 * 10000);
    }
}
// 經理
public class Manager extends Staff {

    public Manager(String name) {
        super(name);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    // 一年做的產品數量
    public int getProducts() {
        return new Random().nextInt(10);
    }
}
// 員工業務報表類(對象結構)
public class BusinessReport {

    private List<Staff> mStaffs = new LinkedList<>();

    public BusinessReport() {
        mStaffs.add(new Manager("經理-A"));
        mStaffs.add(new Engineer("工程師-A"));
        mStaffs.add(new Engineer("工程師-B"));
        mStaffs.add(new Engineer("工程師-C"));
        mStaffs.add(new Manager("經理-B"));
        mStaffs.add(new Engineer("工程師-D"));
    }

    /**
     * 爲訪問者展示報表
     * @param visitor 公司高層,如CEO、CTO
     */
    public void showReport(Visitor visitor) {
        for (Staff staff : mStaffs) {
            staff.accept(visitor);
        }
    }
}
public interface Visitor {

    // 訪問工程師類型
    void visit(Engineer engineer);

    // 訪問經理類型
    void visit(Manager manager);
}
// CEO訪問者
public class CEOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程師: " + engineer.name + ", KPI: " + engineer.kpi);
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("經理: " + manager.name + ", KPI: " + manager.kpi +
                ", 新產品數量: " + manager.getProducts());
    }
}
// CTO訪問者
public class CTOVisitor implements Visitor {
    @Override
    public void visit(Engineer engineer) {
        System.out.println("工程師: " + engineer.name + ", 代碼行數: " + engineer.getCodeLines());
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("經理: " + manager.name + ", 產品數量: " + manager.getProducts());
    }
}

總結

  • 穩定的數據結構和易變的操作耦合問題;將對象本身與對象的訪問操作分離。

  • 優點:
    – 符合單一職責原則。
    – 優秀的擴展性、靈活性。

  • 缺點:
    – 具體元素對訪問者公佈細節,違反了迪米特原則。
    – 違反了依賴倒置原則,依賴了具體類,沒有依賴抽象。

  • 使用場景:
    – 一個對象結構(BusinessReport )包含多個類型(manager、Engineer )的對象,希望對這些對象實施一些依賴其具體類型的操作。不同類型的對象可以有不同的訪問操作。
    – 需要對一個對象結構中的對象進行很多不同的並且不相關的操作,而且需要避免讓這些操作“污染”這些對象的類,也不希望在增加新操作時修改這些類。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章