Java設計模式學習記錄-責任鏈模式
前言
已經把五個創建型設計模式和七個結構型設計模式介紹完了,從這篇開始要介紹行為型設計模式了,第一個要介紹的行為型設計模式就是責任鏈模式(又稱職責鏈模式)。
責任鏈模式
概念介紹
責任鏈模式是為了避免請求的發送者和接收者之間的耦合關系,使多個接收對象都有機會處理請求。將這些對象練成一條鏈,并沿著這條鏈傳遞該請求,直到有一個對象處理它為止。當然責任鏈中也有可能沒有可以處理該請求的對象,這種情況是允許發生的。
舉例
還是以前的規律,先舉出具體的代碼例子,然后再分析。拿前陣子在我老東家發生的一件事情來說,同事小王要結婚了,所以要請假回家籌備婚禮,但是公司有明確的規章制度,請假需要提前申請,并且每一級的領導能夠審批的假期天數也不一樣,部門經理可以審批1到2天的假期,技術總監能夠審批3到5天的假期,大于5天的就要找CEO審批了,如果CEO審批通過了才可以休息5天以上的假期,小王籌備婚禮和渡蜜月總共要請10個工作日的假期。
用代碼來實現這個過程就是下面??這個樣子的。
先創建請假條類
/** * 請假條 */ @Data @AllArgsConstructor public class Leave { /* 部門 */ private String department; /* 員工名稱 */ private String name; /* 請假天數 */ private double days; /* 請假事由 */ private String cause; }
然后創建審批人的抽象類
/** * 審批人 */ public abstract class Approver { /* 審批人名稱 */ String name; /* 下一個審批人 */ Approver nextApprover; public Approver(String name){ this.name = name; } /** * 設置下一個審批人 * @param approver */ public void setNextApprover(Approver approver){ this.nextApprover = approver; } /** * 審批 * @param leave */ public abstract void approval(Leave leave); }
部門經理
/** * 部門經理 */ public class Manager extends Approver { /** * 設置名稱 * @param name 領導名稱 */ public Manager(String name) { super(name); } /** * 審批 * @param leave 請假條 */ @Override public void approval(Leave leave) { if(leave.getDays()<3){ System.out.println("請假小于3天,算臨時休息,批準了。"); System.out.println("部門經理審批通過---------審批流程over。"); }else{ if(Objects.nonNull(nextApprover)){ System.out.println("部門經理批準不了這么多天的假期,需要上級審批。"); this.nextApprover.approval(leave); }else{ System.out.println(name+"的領導不在,等著吧。"); } } } }
技術總監
/** * 技術總監 */ public class TechnicalDirector extends Approver { /** * 設置名稱 * @param name 領導名稱 */ public TechnicalDirector(String name) { super(name); } /** * 審批 * @param leave 請假條 */ @Override public void approval(Leave leave) { if(leave.getDays()<5){ System.out.println("請假小于5天,算有事休息,批準了。"); System.out.println("技術總監審批通過---------審批流程over。"); }else{ if(Objects.nonNull(nextApprover)){ System.out.println("技術總監批準不了這么多天的假期,需要上級審批。"); this.nextApprover.approval(leave); }else{ System.out.println(name+"的領導不在,等著吧。"); } } } }
CEO
/** * CEO */ public class CEO extends Approver { /** * 設置名稱 * @param name 領導名稱 */ public CEO(String name) { super(name); } /** * 審批 * @param leave 請假條 */ @Override public void approval(Leave leave) { if(leave.getDays()>5&&leave.getDays()<=10){ System.out.println("情況特殊,批準了。"); System.out.println("CEO審批通過---------審批流程over。"); }else{ System.out.println(name+"說請假的時間太長了不批,最好別一次性請這么久。"); } } }
測試類
public class Client { public static void main(String[] args) { //寫請假條 Leave leave = new Leave("技術部","小王",6.0,"結婚"); //創建審批節點 Approver zhangge = new Manager("張哥"); Approver laozhao = new TechnicalDirector("老趙"); Approver lizong = new CEO("李總"); //將審批節點串起來 zhangge.setNextApprover(laozhao); laozhao.setNextApprover(lizong); //開始審批 zhangge.approval(leave); } }
運行結果
部門經理批準不了這么多天的假期,需要上級審批。
技術總監批準不了這么多天的假期,需要上級審批。
情況特殊,批準了。
CEO審批通過---------審批流程over。
通過運行結果,我們可以看出來,當請假天數為10天時,部門經理和技術總監都已經處理不了了,然后拋給了CEO,通過CEO特批小王的婚假請求才算了審批完成。這個例子就是用到了我們今天說的責任鏈模式,下面繼續分析責任鏈模式。
責任鏈模式分析
責任鏈的結構圖

主要涉及到的角色
抽象處理者(Handler)角色:抽象處理者用于定義出一個處理請求的接口,如果需要,接口可以定義出一個方法,以返回對下一個處理對象的引用。上面例子中的Approver就是代表的這個角色。
具體處理者(ConcreteHandler)角色:處理接到的請求,可以選擇將請求處理掉,或者將請求傳遞給下家。上面的例子中的Manager和TechnicalDirector以及CEO就是代表的這個角色。
責任鏈模式總結
純的責任鏈模式和不純的責任鏈模式
- 純的責任鏈模式要求一個具體的處理者對象只能在兩個行為中選擇一個:一個是承擔責任;二是把責任推給下家。不允許出現某一個具體處理者對象在承擔了一部分責任后又把責任向下傳的情況。在一個純的責任鏈中,一個請求必須被某一個處理者對象所接受。
- 不純的責任鏈模式中允許某個請求被一個具體處理者部分處理后再向下傳遞,或者一個具體處理者處理完某請求后其后繼處理者可以繼續處理該請求,而且一個請求可以最終不被任何處理者對象所接收。例如JavaScript中的事件冒泡。
責任鏈模式的優點
1、請求不需要指出被哪個對象處理了,這樣的效果是請求者和接收者之間的解耦,而且鏈中的對象也不需要清楚其他鏈的結構,也降低了耦合。
2、請求處理對象僅需要維護一個指向其后繼者的的引用,而不需要維護所有的處理對象,簡化了對象之間的相互連接。
3、在給對象分派職責時,職責鏈可以給我們更多的靈活性,可以通過在運行時對該鏈進行動態的增加或修改來增加或改變處理一個請求的職責。
4、新增一個請求處理對象,不需要改動現有代碼,只需要重新設置連接即可,符合“開閉原則”。
責任鏈模式的缺點
1、如果一個請求沒有明確的接收者,那么就不能保證它一定會被處理,該請求可能一直到鏈的末端都得不到處理;一個請求也可能因職責鏈沒有被正確配置而得不到處理。
2、 對于比較長的職責鏈,請求的處理可能涉及到多個處理對象,不僅增加了代碼的復雜性并且系統性能也將受到一定影響,而且在進行代碼調試時不太方便。
3、若建鏈不當,可能會造成循環調用,將導致系統陷入死循環。
適用場景
1、有多個對象可以處理同一個請求,具體哪個對象處理該請求待運行時刻再確定,客戶端只需將請求提交到鏈上,而無須關心請求的處理對象是誰以及它是如何處理的。
2、在不明確指定接收者的情況下,向多個對象中的一個提交一個請求。
3、可動態指定一組對象處理請求,客戶端可以動態創建職責鏈來處理請求,還可以改變鏈中處理者之間的先后次序。
其實在我們日常開發中也會有適用到責任鏈模式的場景,try/catch、servlet(各個servelt互相調用)、以及filter等
想了解更多的設計模式請查看Java設計模式學習記錄-GoF設計模式概述。
現在是不是行業不景氣呢?怎么最近連面試機會都少了?
作者:紀莫
歡迎任何形式的轉載,但請務必注明出處。
限于本人水平,如果文章和代碼有表述不當之處,還請不吝賜教。
歡迎掃描二維碼關注公眾號:Jimoer
文章會同步到公眾號上面,大家一起成長,共同提升技術能力。
聲援博主:如果您覺得文章對您有幫助,可以點擊文章右下角【推薦】一下。
您的鼓勵是博主的最大動力!


浙公網安備 33010602011771號