鍍金池/ 教程/ Java/ 請求的鏈?zhǔn)教幚怼氊?zé)鏈模式(三)
請求發(fā)送者與接收者解耦——命令模式(四)
對象間的聯(lián)動(dòng)——觀察者模式(三)
算法的封裝與切換——策略模式(三)
請求發(fā)送者與接收者解耦——命令模式(三)
遍歷聚合對象中的元素——迭代器模式(四)
請求的鏈?zhǔn)教幚怼氊?zé)鏈模式(二)
自定義語言的實(shí)現(xiàn)——解釋器模式(五)
操作復(fù)雜對象結(jié)構(gòu)——訪問者模式(一)
處理對象的多種狀態(tài)及其相互轉(zhuǎn)換——狀態(tài)模式(一)
處理對象的多種狀態(tài)及其相互轉(zhuǎn)換——狀態(tài)模式(三)
操作復(fù)雜對象結(jié)構(gòu)——訪問者模式(二)
協(xié)調(diào)多個(gè)對象之間的交互——中介者模式(二)
算法的封裝與切換——策略模式(四)
請求發(fā)送者與接收者解耦——命令模式(六)
撤銷功能的實(shí)現(xiàn)——備忘錄模式(二)
算法的封裝與切換——策略模式(一)
遍歷聚合對象中的元素——迭代器模式(五)
模板方法模式深度解析(三)
協(xié)調(diào)多個(gè)對象之間的交互——中介者模式(五)
自定義語言的實(shí)現(xiàn)——解釋器模式(三)
處理對象的多種狀態(tài)及其相互轉(zhuǎn)換——狀態(tài)模式(六)
遍歷聚合對象中的元素——迭代器模式(三)
操作復(fù)雜對象結(jié)構(gòu)——訪問者模式(四)
遍歷聚合對象中的元素——迭代器模式(一)
算法的封裝與切換——策略模式(二)
請求的鏈?zhǔn)教幚怼氊?zé)鏈模式(一)
遍歷聚合對象中的元素——迭代器模式(二)
操作復(fù)雜對象結(jié)構(gòu)——訪問者模式(三)
對象間的聯(lián)動(dòng)——觀察者模式(六)
對象間的聯(lián)動(dòng)——觀察者模式(五)
請求發(fā)送者與接收者解耦——命令模式(一)
自定義語言的實(shí)現(xiàn)——解釋器模式(六)
自定義語言的實(shí)現(xiàn)——解釋器模式(一)
模板方法模式深度解析(一)
撤銷功能的實(shí)現(xiàn)——備忘錄模式(一)
處理對象的多種狀態(tài)及其相互轉(zhuǎn)換——狀態(tài)模式(五)
請求的鏈?zhǔn)教幚怼氊?zé)鏈模式(三)
遍歷聚合對象中的元素——迭代器模式(六)
撤銷功能的實(shí)現(xiàn)——備忘錄模式(三)
處理對象的多種狀態(tài)及其相互轉(zhuǎn)換——狀態(tài)模式(四)
處理對象的多種狀態(tài)及其相互轉(zhuǎn)換——狀態(tài)模式(二)
協(xié)調(diào)多個(gè)對象之間的交互——中介者模式(四)
對象間的聯(lián)動(dòng)——觀察者模式(二)
請求發(fā)送者與接收者解耦——命令模式(二)
自定義語言的實(shí)現(xiàn)——解釋器模式(四)
對象間的聯(lián)動(dòng)——觀察者模式(四)
撤銷功能的實(shí)現(xiàn)——備忘錄模式(五)
自定義語言的實(shí)現(xiàn)——解釋器模式(二)
協(xié)調(diào)多個(gè)對象之間的交互——中介者模式(三)
協(xié)調(diào)多個(gè)對象之間的交互——中介者模式(一)
撤銷功能的實(shí)現(xiàn)——備忘錄模式(四)
模板方法模式深度解析(二)
撤銷功能的實(shí)現(xiàn)——備忘錄模式(五)
請求發(fā)送者與接收者解耦——命令模式(五)
請求的鏈?zhǔn)教幚怼氊?zé)鏈模式(四)

請求的鏈?zhǔn)教幚怼氊?zé)鏈模式(三)

完整解決方案

為了讓采購單的審批流程更加靈活,并實(shí)現(xiàn)采購單的鏈?zhǔn)絺鬟f和處理,Sunny 公司開發(fā)人員使用職責(zé)鏈模式來實(shí)現(xiàn)采購單的分級(jí)審批,其基本結(jié)構(gòu)如圖所示:

http://wiki.jikexueyuan.com/project/design-pattern-behavior/images/1333307860_9326.gif" alt="采購單分級(jí)審批結(jié)構(gòu)圖" />

在圖中,抽象類 Approver 充當(dāng)抽象處理者(抽象傳遞者),Director、VicePresident、President 和 Congress 充當(dāng)具體處理者(具體傳遞者),PurchaseRequest 充當(dāng)請求類。完整代碼如下所示:

//采購單:請求類
class PurchaseRequest {
    private double amount;  //采購金額
    private int number;  //采購單編號(hào)
    private String purpose;  //采購目的

    public PurchaseRequest(double amount, int number, String purpose) {
        this.amount = amount;
        this.number = number;
        this.purpose = purpose;
    }

    public void setAmount(double amount) {
        this.amount = amount;
    }

    public double getAmount() {
        return this.amount;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public int getNumber() {
        return this.number;
    }

    public void setPurpose(String purpose) {
        this.purpose = purpose;
    }

    public String getPurpose() {
        return this.purpose;
    }
}

//審批者類:抽象處理者
abstract class Approver {
    protected Approver successor; //定義后繼對象
    protected String name; //審批者姓名

    public Approver(String name) {
        this.name = name;
    }

    //設(shè)置后繼者
    public void setSuccessor(Approver successor) { 
        this.successor = successor;
    }

    //抽象請求處理方法
    public abstract void processRequest(PurchaseRequest request);
}

//主任類:具體處理者
class Director extends Approver {
    public Director(String name) {
        super(name);
    }

    //具體請求處理方法
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 50000) {
            System.out.println("主任" + this.name + "審批采購單:" + request.getNumber() + ",金額:" + request.getAmount() + "元,采購目的:" + request.getPurpose() + "。");  //處理請求
        }
        else {
            this.successor.processRequest(request);  //轉(zhuǎn)發(fā)請求
        }   
    }
}

//副董事長類:具體處理者
class VicePresident extends Approver {
    public VicePresident(String name) {
        super(name);
    }

    //具體請求處理方法
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 100000) {
            System.out.println("副董事長" + this.name + "審批采購單:" + request.getNumber() + ",金額:" + request.getAmount() + "元,采購目的:" + request.getPurpose() + "。");  //處理請求
        }
        else {
            this.successor.processRequest(request);  //轉(zhuǎn)發(fā)請求
        }   
    }
}

//董事長類:具體處理者
class President extends Approver {
    public President(String name) {
        super(name);
    }

    //具體請求處理方法
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 500000) {
            System.out.println("董事長" + this.name + "審批采購單:" + request.getNumber() + ",金額:" + request.getAmount() + "元,采購目的:" + request.getPurpose() + "。");  //處理請求
        }
        else {
            this.successor.processRequest(request);  //轉(zhuǎn)發(fā)請求
        }
    }
}

//董事會(huì)類:具體處理者
class Congress extends Approver {
    public Congress(String name) {
        super(name);
    }

    //具體請求處理方法
    public void processRequest(PurchaseRequest request) {
        System.out.println("召開董事會(huì)審批采購單:" + request.getNumber() + ",金額:" + request.getAmount() + "元,采購目的:" + request.getPurpose() + "。");        //處理請求
    }    
}

編寫如下客戶端測試代碼:

class Client {
    public static void main(String[] args) {
        Approver wjzhang,gyang,jguo,meeting;
        wjzhang = new Director("張無忌");
        gyang = new VicePresident("楊過");
        jguo = new President("郭靖");
        meeting = new Congress("董事會(huì)");

        //創(chuàng)建職責(zé)鏈
        wjzhang.setSuccessor(gyang);
        gyang.setSuccessor(jguo);
        jguo.setSuccessor(meeting);

        //創(chuàng)建采購單
        PurchaseRequest pr1 = new PurchaseRequest(45000,10001,"購買倚天劍");
        wjzhang.processRequest(pr1);

        PurchaseRequest pr2 = new PurchaseRequest(60000,10002,"購買《葵花寶典》");
        wjzhang.processRequest(pr2);

        PurchaseRequest pr3 = new PurchaseRequest(160000,10003,"購買《金剛經(jīng)》");
        wjzhang.processRequest(pr3);

        PurchaseRequest pr4 = new PurchaseRequest(800000,10004,"購買桃花島");
        wjzhang.processRequest(pr4);
    }
} 

編譯并運(yùn)行程序,輸出結(jié)果如下:

主任張無忌審批采購單:10001,金額:45000.0元,采購目的:購買倚天劍。
副董事長楊過審批采購單:10002,金額:60000.0元,采購目的:購買《葵花寶典》。
董事長郭靖審批采購單:10003,金額:160000.0元,采購目的:購買《金剛經(jīng)》。
召開董事會(huì)審批采購單:10004,金額:800000.0元,采購目的:購買桃花島。

如果需要在系統(tǒng)增加一個(gè)新的具體處理者,如增加一個(gè)經(jīng)理(Manager)角色可以審批 5 萬元至 8 萬元(不包括 8 萬元)的采購單,需要編寫一個(gè)新的具體處理者類 Manager,作為抽象處理者類 Approver 的子類,實(shí)現(xiàn)在 Approver 類中定義的抽象處理方法,如果采購金額大于等于 8 萬元,則將請求轉(zhuǎn)發(fā)給下家,代碼如下所示:

//經(jīng)理類:具體處理者
class Manager extends Approver {
    public Manager(String name) {
        super(name);
    }

    //具體請求處理方法
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 80000) {
            System.out.println("經(jīng)理" + this.name + "審批采購單:" + request.getNumber() + ",金額:" + request.getAmount() + "元,采購目的:" + request.getPurpose() + "。");  //處理請求
        }
        else {
            this.successor.processRequest(request);  //轉(zhuǎn)發(fā)請求
        }   
    }
}

由于鏈的創(chuàng)建過程由客戶端負(fù)責(zé),因此增加新的具體處理者類對原有類庫無任何影響,無須修改已有類的源代碼,符合“開閉原則”。

在客戶端代碼中,如果要將新的具體請求處理者應(yīng)用在系統(tǒng)中,需要?jiǎng)?chuàng)建新的具體處理者對象,然后將該對象加入職責(zé)鏈中。如在客戶端測試代碼中增加如下代碼:

Approver rhuang;
rhuang = new Manager("黃蓉");

將建鏈代碼改為:

//創(chuàng)建職責(zé)鏈
wjzhang.setSuccessor(rhuang); //將“黃蓉”作為“張無忌”的下家
rhuang.setSuccessor(gyang); //將“楊過”作為“黃蓉”的下家
gyang.setSuccessor(jguo);
jguo.setSuccessor(meeting);

重新編譯并運(yùn)行程序,輸出結(jié)果如下:

主任張無忌審批采購單:10001,金額:45000.0元,采購目的:購買倚天劍。
經(jīng)理黃蓉審批采購單:10002,金額:60000.0元,采購目的:購買《葵花寶典》。
董事長郭靖審批采購單:10003,金額:160000.0元,采購目的:購買《金剛經(jīng)》。
召開董事會(huì)審批采購單:10004,金額:800000.0元,采購目的:購買桃花島。

思考

如果將審批流程由“主任-->副董事長-->董事長-->董事會(huì)”調(diào)整為“主任-->董事長-->董事會(huì)”,系統(tǒng)將做出哪些改動(dòng)?預(yù)測修改之后客戶端代碼的輸出結(jié)果。