常用的設計模式之訪問者模式

訪問者模式(Visitor Pattern) 是一種將數據結構與數據操作分離的設計模式。是指封裝一

些作用於某種數據結構中的各元素的操作,它可以在不改變數據結構的前提下定義作用於這些

元素的新的操作。屬於行爲型模式。

原文:Represent an operation to be performed on the elements of an object structure.Visitor lets you define a new operation without changing the classes of the elements on which it operates...o

訪問者模式被稱爲最複雜的設計模式,並且使用頻率不高,設計模式的作者也評價爲:大多

情況下,你不需要使用訪問者模式,但是一旦需要使用它時,那就真的需要使用了。訪問者模

式的基本思想是, 針對系統中擁有固定類型數的對象結構(元素) , 在其內提供一個accept()

方法用來接受訪問者對象的訪問。不同的訪問者對同一元素的訪問內容不同,使得相同的元素

集合可以產生不同的數據結果。accept() 方法可以接收不同的訪問者對象, 然後在內部將自己(元

素) 轉發到接收到的訪問者對象的visit() 方法內。訪問者內部對應類型的visit() 方法就會得到回

調執行, 對元素進行操作。也就是通過兩次動態分發(第一次是對訪問者的分發accept() 方法,

第二次是對元素的分發visit() 方法) , 才最終將一個具體的元素傳遞到一個具體的訪問者。如此

一來,就解耦了數據結構與操作,且數據操作不會改變元素狀態。

訪問者模式的核心是,解耦數據結構與數據操作,使得對元素的操作具備優秀的擴展性。可

以通過擴展不同的數據操作類型(訪問者)實現對相同元素集的不同的操作。

解耦數據結構和數據操作,

類比

食堂裏的座位,吃放工具,窗口(數據結構固定的), 進來吃飯的人就是訪問者他們來操作上面的數 據是不固定的,

kpi考覈 其組織方式是固定的(),查看kpi的人和被考查的人的方式是不固定的

類圖:

在這裏插入圖片描述

代碼:

訪問者接口

public interface IVisitor {

    void visit(Engineer engineer);

    void visit(Manager manager);

}

被考覈者的抽象類Employee

public abstract class Employee {
    public String name;
    public int kpi;  //員工KPI

    public Employee(String name) {
        this.name = name;
        kpi = new Random().nextInt(10);
    }

    //接收訪問者的訪問
    public abstract void accept(IVisitor visitor);
}

被考覈者角色普通工程師Engineer

public class Engineer extends Employee {
    public Engineer(String name) {
        super(name);
    }

    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }

    //考覈指標是每年的代碼量
    public int getCodeLines(){
        return new Random().nextInt(10* 10000);
    }
}

被考覈者角色產品經理Manager

public class Manager extends Employee {
    public Manager(String name) {
        super(name);
    }

    public void accept(IVisitor visitor) {
        visitor.visit(this);
    }

    //考覈的是每年新產品研發數量
    public int getProducts(){
        return new Random().nextInt(10);
    }
}

查看考覈成績的角色CEOVistitor

public class CEOVistitor implements IVisitor {
    public void visit(Engineer engineer) {
        System.out.println("工程師" +  engineer.name + ",KIP:" + engineer.kpi);
    }

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

查看考覈成績的角色CTOVistitor

public class CTOVistitor implements IVisitor {
    public void visit(Engineer engineer) {
        System.out.println("工程師" +  engineer.name + ",代碼行數:" + engineer.getCodeLines());
    }

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

報表的方法BusinessReport

public class BusinessReport {
    private List<Employee> employees = new LinkedList<Employee>();

    public BusinessReport() {
        employees.add(new Manager("產品經理A"));
        employees.add(new Engineer("程序員A"));
        employees.add(new Engineer("程序員B"));
        employees.add(new Engineer("程序員C"));
        employees.add(new Manager("產品經理B"));
        employees.add(new Engineer("程序員D"));
    }

    public void showReport(IVisitor visitor){
        for (Employee employee : employees) {
            employee.accept(visitor);
        }
    }
}

測試方法:

public class Test {
    public static void main(String[] args) {
        BusinessReport report = new BusinessReport();
        System.out.println("==========CEO看報表===============");
        report.showReport(new CEOVistitor());
        System.out.println("==========CTO看報表===============");
        report.showReport(new CTOVistitor());
    }
}

測試結果:
在這裏插入圖片描述

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