請求的鏈式處理——職責鏈模式(三)

Liuwei-Sunny發表於2012-04-02

16.3 完整解決方案

      為了讓採購單的審批流程更加靈活,並實現採購單的鏈式傳遞和處理,Sunny公司開發人員使用職責鏈模式來實現採購單的分級審批,其基本結構如圖16-3所示:

       在圖16-3中,抽象類Approver充當抽象處理者(抽象傳遞者),DirectorVicePresidentPresidentCongress充當具體處理者(具體傳遞者),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

 

相關文章