- //本文作者:凸凹里歐
- //本文收錄菜單欄:《設計模式是什么鬼》專欄中
曾經有這么一些零散的功能節點,他們各自承擔各自的義務,分工明確,各司其職。為了更高效,更完整地解決客戶的問題,他們發揚團隊精神,互相串聯起來形成一個有序的責任傳遞鏈表,於是責任鏈模式誕生了。當然,它的結構也不一定非得是鏈表,甚至可以是樹型分叉結構,這要根據業務場景看怎樣去靈活運用,但其核心意義是為了處理某種連續的流程,並確保業務一定能走到相應的責任節點上並得到相應的處理。
說到這里想必大家已經想到了工作流吧?對,企事業單位中通常為了完成某項日常任務,通常要制定一些工作流程,按步驟拆分,並組織好各個環節中的邏輯關系及走向,這樣才能更高效、更規范地完成任務。
根據以上流程圖,我們來做一個最簡單的例子。假設某公司針對出差報銷業務制定審批流程,有三個審批角色分別是員工(1000元權限)、經理(5000元權限)、以及CEO(10000元權限),各審批人代碼如下。
public class Staff { private String name; public Staff(String name) { this.name = name; } public boolean approve(int amount) { if (amount <= 1000) { System.out.println("審批通過。【員工:" + name + "】"); return true; } else { System.out.println("無權審批,請找上級。【員工:" + name + "】"); return false; } } }
public class Manager { private String name; public Manager(String name) { this.name = name; } public boolean approve(int amount) { if (amount <= 5000) { System.out.println("審批通過。【經理:" + name + "】"); return true; } else { System.out.println("無權審批,請找上級。【經理:" + name + "】"); return false; } } }
public class CEO { private String name; public CEO(String name) { this.name = name; } public boolean approve(int amount) { if (amount <= 10000) { System.out.println("審批通過。【CEO:" + name + "】"); return true; } else { System.out.println("駁回申請。【CEO:" + name + "】"); return false; } } }
好了,審批人們定義完畢,邏輯非常簡單縝密,如果超過審批金額最大權限則打回去,開始寫申請人客戶端類。
public class Client { public static void main(String[] args) { int amount = 10000;//出差花費10000元 // 先找員工張飛審批 Staff staff = new Staff("張飛"); if (!staff.approve(amount)) { //被拒,找關二爺問問。 Manager manager = new Manager("關羽"); if (!manager.approve(amount)) { //還是被拒,只能找老大了。 CEO ceo = new CEO("劉備"); ceo.approve(amount); } } /*********************** 無權審批,請找上級。【員工:張飛】 無權審批,請找上級。【經理:關羽】 審批通過。【CEO:劉備】 ***********************/ } }
功夫不負有心人,跑了三個地方找了三個人,一萬元的大額報銷單終於被大老板審批了。然而,大家有沒有發現問題?我們走的審批流程好像有點過於復雜了,找這個不行那個不同意,跑來跑去的好像自己有點像是被踢皮球的感覺。此外,如果我們后期要優化完善此工作流程,或是添加新的審批角色進來,那就得不停地修改此處的邏輯,最終的修改結果會是?
亂了,全亂套了,我們終將被淹沒在一堆復雜的審批流程中,跑斷腿也找不到門路。這顯然是違反設計模式原則的,我們必須進行重構。我們觀察此類中的審批邏輯,這顯然就是一個鏈式結構,審批人之間環環相扣,對於自己無法處理的申請,會像被踢皮球似的傳給上級,直到某人解決此申請,對員工張飛來說,他只知道自己傳球給關羽了,僅此而已。
進一步分析,審批人肯定是不同的角色,並且每個角色的審批邏輯會有區別,所以我們得把這些角色的審批邏輯分開來寫,對每個角色的責任范圍我們進行定義,我只懂自己怎么審批(責任),我處理不了的我遞交給上層(鏈條),開始重構,先抽象出一個審批人類。
public abstract class Approver {// 審批人抽象類 protected String name;// 抽象出審批人的姓名。 protected Approver nextApprover;// 下一個審批人,更高級別領導。 public Approver(String name) { this.name = name; } protected Approver setNextApprover(Approver nextApprover) { this.nextApprover = nextApprover; return this.nextApprover;// 返回下個審批人,鏈式編程。 } public abstract void approve(int amount);// 抽象審批方法由具體審批人子類實現 }
注意第4行,審批人只認識自己的領導,所以會持有下一級領導的引用,同時第10行的代碼用於把領導注入進來。第15行是我們的審批方法了,但每個角色審批邏輯會有區別,所以這里進行抽象,並由具體的審批角色子類去實現,先從員工看起。
public class Staff extends Approver { public Staff(String name) { super(name); } @Override public void approve(int amount) { if (amount <= 1000) { System.out.println("審批通過。【員工:" + name + "】"); } else { System.out.println("無權審批,升級處理。【員工:" + name + "】"); this.nextApprover.approve(amount); } } }
很簡單,員工類繼承了審批角色類,第9行申明審批權限為1000元,重點在於第13行這里調用了自己上級領導的審批方法,顯然這里是自己處理不了的申請單了。大同小異,再重構經理及CEO審批角色類。
public class Manager extends Approver { public Manager(String name) { super(name); } @Override public void approve(int amount) { if (amount <= 5000) { System.out.println("審批通過。【經理:" + name + "】"); } else { System.out.println("無權審批,升級處理。【經理:" + name + "】"); this.nextApprover.approve(amount); } } }
public class CEO extends Approver { public CEO(String name) { super(name); } @Override public void approve(int amount) { if (amount <= 10000) { System.out.println("審批通過。【CEO:" + name + "】"); } else { System.out.println("駁回申請。【CEO:" + name + "】"); } } }
CEO類作為鏈條的尾巴,也就是最高級別,第12行的越權邏輯會最終拒絕申請單。很簡單吧?我們生成一下這個鏈條,並從員工開始傳遞申請單。
public class Client { public static void main(String[] args) { Approver flightJohn = new Staff("張飛"); flightJohn.setNextApprover(new Manager("關羽")).setNextApprover(new CEO("劉備")); //高層接觸不到也沒必要接觸,直接找員工張飛審批。 flightJohn.approve(1000); /*********************** 審批通過。【員工:張飛】 ***********************/ flightJohn.approve(4000); /*********************** 無權審批,升級處理。【員工:張飛】 審批通過。【經理:關羽】 ***********************/ flightJohn.approve(9000); /*********************** 無權審批,升級處理。【員工:張飛】 無權審批,升級處理。【經理:關羽】 審批通過。【CEO:劉備】 ***********************/ flightJohn.approve(88000); /*********************** 無權審批,升級處理。【員工:張飛】 無權審批,升級處理。【經理:關羽】 駁回申請。【CEO:劉備】 ***********************/ } }
這里注意第4行的代碼對責任鏈進行構造(其實這里我們還可以交由工作流工廠去構造完成,讀者可以自己實踐練習),從員工開始一直到CEO結束。之后的業務就非常簡單了,直接遞單給員工張飛,審批流程便魔法般地啟動了,審批單在這個責任鏈條上層層遞交,最終給出結果。
至此,申請人與審批人實現了解耦,我們只需遞單送給責任鏈即可,申請人不必再關心每個處理細節,只需交給接口人張飛處理就妥了。使用了責任鏈模式后的代碼看起來非常簡潔,各個角色的責任划分非常明確並且被分開定義到了每個角色類中,再把他們串起來去調用,一氣呵成。后期如果再繼續添加新的角色只需要添加新角色類並加入鏈條即可,鏈條的隨意伸縮,靈活的可伸縮性,完美的可擴展性。掛上這條鈦合金項鏈,維護世界和平的責任就交給你了!
在實際應用中,我們切勿生搬硬套,還需根據實際需求場景進行靈活運用,就拿工業現代化生產線舉例,這個其實也類似責任鏈模式,但不同之處在於其組裝工作是必須經過每個組裝節點處理的,從頭到尾的全鏈處理而不能中途退出,讀者朋友可以自己寫代碼練習,實踐與思考要相結合並循環往復,二者都非常重要。