16.3 完整解決方案
為了讓採購單的審批次程序更加靈活,並實現採購單的鏈式傳遞和處理,Sunny公司開發人員使用職責鏈模式來實現採購單的分級審批,其基本結構16-3所示:
在圖16-3中,抽象類別Approver充當抽象處理者(抽象傳遞者),Director、VicePresident、President和Congress充當具體處理者(具體傳遞者),PurchaseRequest充當請求類。完整代碼如下所示:
//採購單:請求類class PurchaseRequest {private double amount; //採購金額private int number; //採購單編號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;}//設定後繼者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); //轉寄請求 } }}//副董事長類:具體處理者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); //轉寄請求 } }}//董事長類:具體處理者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); //轉寄請求 } }}//董事會類:具體處理者class Congress extends Approver {public Congress(String name) {super(name);} //具體請求處理方法 public void processRequest(PurchaseRequest request) { System.out.println("召開董事會審批採購單:" + 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("董事會");//建立職責鏈wjzhang.setSuccessor(gyang);gyang.setSuccessor(jguo);jguo.setSuccessor(meeting);//建立採購單PurchaseRequest pr1 = new PurchaseRequest(45000,10001,"購買倚天劍");wjzhang.processRequest(pr1);PurchaseRequest pr2 = new PurchaseRequest(60000,10002,"購買《葵花寶典》");wjzhang.processRequest(pr2);PurchaseRequest pr3 = new PurchaseRequest(160000,10003,"購買《金剛經》");wjzhang.processRequest(pr3);PurchaseRequest pr4 = new PurchaseRequest(800000,10004,"購買桃花島");wjzhang.processRequest(pr4);}} 編譯並運行程式,輸出結果如下:
主任張無忌審批採購單:10001,金額:45000.0元,採購目的:購買倚天劍。 副董事長楊過審批採購單:10002,金額:60000.0元,採購目的:購買《葵花寶典》。 董事長郭靖審批採購單:10003,金額:160000.0元,採購目的:購買《金剛經》。 召開董事會審批採購單:10004,金額:800000.0元,採購目的:購買桃花島。 |
如果需要在系統增加一個新的具體處理者,如增加一個經理(Manager)角色可以審批5萬元至8萬元(不包括8萬元)的採購單,需要編寫一個新的具體處理者類Manager,作為抽象處理者類Approver的子類,實現在Approver類中定義的抽象處理方法,如果採購金額大於等於8萬元,則將請求轉寄給下家,代碼如下所示:
//經理類:具體處理者class Manager extends Approver {public Manager(String name) {super(name);} //具體請求處理方法 public void processRequest(PurchaseRequest request) { if (request.getAmount() < 80000) { System.out.println("經理" + this.name + "審批採購單:" + request.getNumber() + ",金額:" + request.getAmount() + "元,採購目的:" + request.getPurpose() + "。"); //處理請求 } else { this.successor.processRequest(request); //轉寄請求 } }}
由於鏈的建立過程由用戶端負責,因此增加新的具體處理者類對原有類庫無任何影響,無須修改已有類的原始碼,符合“開閉原則”。
在用戶端代碼中,如果要將新的具體請求處理者應用在系統中,需要建立新的具體處理者對象,然後將該對象加入職責鏈中。如在用戶端測試代碼中增加如下代碼:
Approver rhuang;rhuang = new Manager("黃蓉");
將建鏈代碼改為:
//建立職責鏈wjzhang.setSuccessor(rhuang); //將“黃蓉”作為“張無忌”的下家rhuang.setSuccessor(gyang); //將“楊過”作為“黃蓉”的下家gyang.setSuccessor(jguo);jguo.setSuccessor(meeting);
重新編譯並運行程式,輸出結果如下:
主任張無忌審批採購單:10001,金額:45000.0元,採購目的:購買倚天劍。 經理黃蓉審批採購單:10002,金額:60000.0元,採購目的:購買《葵花寶典》。 董事長郭靖審批採購單:10003,金額:160000.0元,採購目的:購買《金剛經》。 召開董事會審批採購單:10004,金額:800000.0元,採購目的:購買桃花島。 |
|
思考 如果將審批次程序由“主任-->副董事長-->董事長-->董事會”調整為“主任-->董事長-->董事會”,系統將做出哪些改動?預測修改之後用戶端代碼的輸出結果。 |
|
【作者:劉偉 http://blog.csdn.net/lovelion】