訪問者模式

定義

封裝一些作用于某種數據結構中的各元素的操作,它可以在不改變這個暑假結構的前提下定義作用于這些元素的新的操作

使用場景

  • 對象結構比較穩定,但經常需要再此對象上定義新的操作
  • 需要對一個對象結構中的對象進行很多不同的并且不想關的操作,而需要避免這些操作“污染”這些對象的類,也不希望在新增操作時修改這些類

結構

  • visitor 接口或抽象類
    定義了對每一個元素訪問的行為,它的參數就是可以訪問的元素

  • ConcreteVisitor 具體訪問者
    給出每一個元素類訪問時產生的具體行為

  • Element 元素接口或抽象接口
    定義了一個接受訪問者的方法,其意義是指每個元素都要可以被訪問者訪問

  • ElementA、ElementB 具體元素類
    提供接受訪問者的具體實現

  • ObjectStructure 定義當中所提到的對象結果
    它內部管理了元素集合,并且可以迭代這些元素供訪問者訪問

簡單實現


public interface Visitor {

    void visit(Engineer engineer);

    void visit(Manager manager);
}

Visitor定義了一個visitor接口,有2個visit函數,對于Engineer、Manager的訪問會調用2個不同的方法,以此達到差異化處理

public abstract class Staff {

    public String name;

    public int kpi;

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

    public abstract void accept(Visitor visitor);
}

Staff為員工基類,定義了一個accept方法用來表示接受訪問者訪問,由子類具體實現

public class Manager extends Staff {
    private int products;

    public Manager(String name) {
        super(name);
        products = new Random().nextInt(10);
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public int getProducts() {
        return products;
    }
}

Manager為經理類

public class Engineer extends Staff {


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

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }


    /**
     * @return 工程師這一年的代碼數量
     */
    public int getCodeLines() {
        return new Random().nextInt(10 * 10000);
    }

}

Engineer為工程師類

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());
    }
}

CTOVisitor為CTO訪問者,關心技術貢獻

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());
    }
}

CEOVisitor為CEO訪問者 只關注業績

public class BusinessReport {

    List<Staff> mStaff = new LinkedList<>();

    public BusinessReport() {
        mStaff.add(new Manager("王經理"));
        mStaff.add(new Engineer("工程師-Shawn.Xiong"));
        mStaff.add(new Engineer("工程師-Kael"));
        mStaff.add(new Engineer("工程師-Jack"));
        mStaff.add(new Engineer("工程師-Rose"));
    }

    /**
     * 為訪問者展示報表
     * @param visitor
     */
    public void showReport(Visitor visitor) {
        for (Staff staff : mStaff) {
            staff.accept(visitor);
        }
    }
}

BusinessReport為員工業務報表,訪問者可以通過showReport函數查看所有員工的業績

public class Client {
    public static void main(String[] args) {
        BusinessReport report = new BusinessReport();

        System.out.println("---------- 給 CEO 看的報表 -------------");

        report.showReport(new CEOVisitor());

        System.out.println("\n---------- 給 CTO 看的報表 -------------");

        report.showReport(new CTOVisitor());
    }
}

運行結果:

---------- 給 CEO 看的報表 -------------
經理 :王經理 , KPI0 ,新產品數量 :3
工程師 :工程師-Shawn.Xiong , KPI6
工程師 :工程師-Kael , KPI4
工程師 :工程師-Jack , KPI1
工程師 :工程師-Rose , KPI2

---------- 給 CTO 看的報表 -------------
經理 :王經理 ,新產品數量 :3
工程師 :工程師-Shawn.Xiong , 代碼行數67720
工程師 :工程師-Kael , 代碼行數37258
工程師 :工程師-Jack , 代碼行數96044
工程師 :工程師-Rose , 代碼行數3708
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容