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

Liuwei-Sunny發表於2012-04-02

      “一對二”,“過”,“過”……這聲音熟悉嗎?你會想到什麼?對!紙牌。在類似“鬥地主”這樣的紙牌遊戲中,某人出牌給他的下家,下家看看手中的牌,如果要不起上家的牌則將出牌請求再轉發給他的下家,其下家再進行判斷。一個迴圈下來,如果其他人都要不起該牌,則最初的出牌者可以打出新的牌。在這個過程中,牌作為一個請求沿著一條鏈在傳遞,每一位紙牌的玩家都可以處理該請求。在設計模式中,我們也有一種專門用於處理這種請求鏈式傳遞的模式,它就是本章將要介紹的職責鏈模式。

 

16.1 採購單的分級審批

      Sunny軟體公司承接了某企業SCM(Supply Chain Management,供應鏈管理)系統的開發任務,其中包含一個採購審批子系統。該企業的採購審批是分級進行的,即根據採購金額的不同由不同層次的主管人員來審批,主任可以審批5萬元以下(不包括5萬元)的採購單,副董事長可以審批5萬元至10萬元(不包括10萬元)的採購單,董事長可以審批10萬元至50萬元(不包括50萬元)的採購單,50萬元及以上的採購單就需要開董事會討論決定。如圖16-1所示:

16-1 採購單分級審批示意圖

      如何在軟體中實現採購單的分級審批?Sunny軟體公司開發人員提出了一個初始解決方案,在系統中提供一個採購單處理類PurchaseRequestHandler用於統一處理採購單,其框架程式碼如下所示:

//採購單處理類
class PurchaseRequestHandler {
	//遞交採購單給主任
	public void sendRequestToDirector(PurchaseRequest request) {
		if (request.getAmount() < 50000) {
			//主任可審批該採購單
			this.handleByDirector(request);
		}
		else if (request.getAmount() < 100000) {
			//副董事長可審批該採購單
			this.handleByVicePresident(request);
		}
		else if (request.getAmount() < 500000) {
			//董事長可審批該採購單
			this.handleByPresident(request);
		}
		else {
			//董事會可審批該採購單
			this.handleByCongress(request);
		}
	}
	
	//主任審批採購單
	public void handleByDirector(PurchaseRequest request) {
		//程式碼省略
	}
	
	//副董事長審批採購單
	public void handleByVicePresident(PurchaseRequest request) {
		//程式碼省略
	}
	
	//董事長審批採購單
	public void handleByPresident(PurchaseRequest request) {
		//程式碼省略
	}
	
	//董事會審批採購單
	public void handleByCongress(PurchaseRequest request) {
		//程式碼省略
	}
}

        問題貌似很簡單,但仔細分析,發現上述方案存在如下幾個問題:

       (1)PurchaseRequestHandler類較為龐大,各個級別的審批方法都集中在一個類中,違反了“單一職責原則”,測試和維護難度大。

       (2)如果需要增加一個新的審批級別或調整任何一級的審批金額和審批細節(例如將董事長的審批額度改為60萬元)時都必須修改原始碼並進行嚴格測試,此外,如果需要移除某一級別(例如金額為10萬元及以上的採購單直接由董事長審批,不再設副董事長一職)時也必須對原始碼進行修改,違反了“開閉原則”。

       (3)審批流程的設定缺乏靈活性,現在的審批流程是“主任-->副董事長-->董事長-->董事會”,如果需要改為“主任-->董事長-->董事會”,在此方案中只能通過修改原始碼來實現,客戶端無法定製審批流程。

       如何針對上述問題對系統進行改進?Sunny公司開發人員迫切需要一種新的設計方案,還好有職責鏈模式,通過使用職責鏈模式我們可以最大程度地解決這些問題,下面讓我們正式進入職責鏈模式的學習。

【作者:劉偉  http://blog.csdn.net/lovelion

 

相關文章