為了讓采購單的審批流程更加靈活,并實(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é)果。