一文帶你徹底搞懂什么是責任鏈模式!!

文章目錄

    • 什么是責任鏈模式?
    • 詳細示例
    • SpingMVC 中的責任鏈模式使用
    • 總結

在這里插入圖片描述

什么是責任鏈模式?

在我們日常生活中,經常會出現一種場景:一個請求需要經過多個對象的處理才能得到最終的結果。比如,一個請假申請,需要經過組長、部門經理、總經理等多個級別的審批。這種場景下,使用責任鏈模式是一種非常優雅的解決方案。

責任鏈模式(Chain of Responsibility Pattern)是一種行為型設計模式,它的主要目的是將請求的發送者和接收者解耦,使得多個對象都有機會處理這個請求。這種模式通過將請求沿著處理者鏈進行傳遞,直到有一個對象處理它為止。

在這里插入圖片描述

在責任鏈模式中,主要涉及以下三個角色:

  1. 抽象處理者(Handler):處理器抽象接口,定義了處理請求的方法和執行下一步處理的處理器。
  2. 具體處理者(ConcreteHandler):實現抽象處理者接口,具體處理請求的邏輯在這里實現。如果不能處理當前請求,則將請求傳遞給下一個處理者。
  3. 客戶端(Client):負責創建并組裝責任鏈,將請求發送給鏈中的第一個處理者。

在這里插入圖片描述

在這里插入圖片描述

代碼:

// 抽象處理器
public abstract class Handler {private Handler next;public Handler getNext() {return next;}public void setNext(Handler next) {this.next = next;}public abstract void handle(Object request);
}// 具體處理器 1
public class ConcreteHandler1 extends Handler {@Overridepublic void handle(Object request) {System.out.println("concrete handler 1 execute request. request: " + request);if (getNext() != null) {getNext().handle(request);}}
}// 具體處理器 2
public class ConcreteHandler2 extends Handler {@Overridepublic void handle(Object request) {System.out.println("concrete handler 2 execute request. request: " + request);if (getNext() != null){getNext().handle(request);}}
}// 具體處理器 3
public class ConcreteHandler3 extends Handler {@Overridepublic void handle(Object request) {System.out.println("concrete handler 3 execute request. request: " + request);if (getNext() != null) {getNext().handle(request);}}
}public static void main(String[] args) {Handler concreteHandler1 = new ConcreteHandler1();Handler concreteHandler2 = new ConcreteHandler2();Handler concreteHandler3 = new ConcreteHandler3();concreteHandler1.setNext(concreteHandler2);concreteHandler2.setNext(concreteHandler3);concreteHandler1.handle("my request.");
}

從上面的代碼我們可以看到其實責任鏈模式是非常簡單的,但是其中有幾個點需要注意一下:

  • 首先我們需要對整個責任鏈進行初始化,即設置每個處理器的 next
  • 在每個具體處理器處理完之后需要手動調用下一個處理器的 handle 方法來執行下一步處理,這里其實還可以使用模板方法模式進行優化

控制臺輸出如下:

concrete handler 1 execute request. request: my request.
concrete handler 2 execute request. request: my request.
concrete handler 3 execute request. request: my request.

詳細示例

日常請假為例。請假申請會先到你的直屬 leader 處審批,審批通過后再到部門 leader 處審批,部門 leader 通過后,最后到人事處報備記錄請假天數。

如果在傳統企業里面,我們需要手寫一份請假表,然后跑到直屬 leader 辦公室,讓直屬 leader 簽字,然后再到部門 leader 辦公室簽字,最后還要跑到人事處上交請假單,這樣相當于發出了三次請求,才能走完整個請假流程。

在這里插入圖片描述

但是當我們使用責任鏈模式后整個請假流程就變的簡單了,我們只需要發起一次請假請求,接下來你的請假請求便會自動的在審批人中間進行流轉,這個時候我們的責任鏈模式便派上用場。

在這里插入圖片描述

代碼如下:

// 請假抽象處理器
public abstract class DayOffHandler {private DayOffHandler next;public DayOffHandler getNext() {return next;}public void setNext(DayOffHandler next) {this.next = next;}public abstract void handle(String request);}
// 直屬 leader 處理
public class GroupLeaderHandler extends DayOffHandler {@Overridepublic void handle(String request) {System.out.println("直屬 leader 審查: " + request);System.out.println("同意請求");if (getNext() != null) {getNext().handle(request);}}
}
// 部門 leader 處理
public class DepartmentLeaderHandler extends DayOffHandler{@Overridepublic void handle(String request) {System.out.println("部門 leader 審查: " + request);System.out.println("同意請求");if (getNext() != null) {getNext().handle(request);}}
}
// 人事處處理
public class HRHandler extends DayOffHandler {@Overridepublic void handle(String request) {System.out.println("人事處審查: " + request);System.out.println("同意請求,記錄請假");if (getNext() != null) {getNext().handle(request);}}
}

客戶端:

public static void main(String[] args) {DayOffHandler groupLeaderHandler = new GroupLeaderHandler();DayOffHandler departmentLeaderHandler = new DepartmentLeaderHandler();DayOffHandler hrHandler = new HRHandler();groupLeaderHandler.setNext(departmentLeaderHandler);departmentLeaderHandler.setNext(hrHandler);System.out.println("收到面試通知,需要請假");String request = "家中有事,請假半天,望批準";System.out.println("發起請求:");groupLeaderHandler.handle(request);
}

上面的代碼定義了請假抽象處理類和三個具體的處理人,我們需要將這三個處理人的流程初始化串聯起來,并且一步步的執行下去

結果:

收到面試通知,需要請假
發起請求:
直屬 leader 審查: 家中有事,請假半天,望批準
同意請求
部門 leader 審查: 家中有事,請假半天,望批準
同意請求
人事處審查: 家中有事,請假半天,望批準
同意請求,記錄請假

SpingMVC 中的責任鏈模式使用

在 SpringMVC 中的 Interceptor 用到了責任鏈模式。首先來看看 Interceptor 的抽象處理類;

public interface HandlerInterceptor {default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {}default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}
}

在抽象處理類中,定義了三個方法,分別是處理前置處理器、后置處理器和整個流程完成之后的處理。通過 HandlerExecutionChain 將攔截器串聯起來,在 HandlerExecutionChain 中,我們需要關注 applyPreHandleapplyPostHandletriggerAfterCompletion 三個方法,這三個方法分別執行了攔截器中所定義的 preHandlepostHandleafterCompletion 方法。并且從代碼中也能夠看處,和前面的過濾器一樣,所有的攔截器都存放在 interceptors 數組中,并在三個方法中遍歷 interceptors 數組依次執行相應的方法

public class HandlerExecutionChain {@Nullableprivate HandlerInterceptor[] interceptors;boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {HandlerInterceptor[] interceptors = this.getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {HandlerInterceptor interceptor = interceptors[i];if (!interceptor.preHandle(request, response, this.handler)) {this.triggerAfterCompletion(request, response, (Exception)null);return false;}}}return true;}void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {HandlerInterceptor[] interceptors = this.getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for(int i = interceptors.length - 1; i >= 0; --i) {HandlerInterceptor interceptor = interceptors[i];interceptor.postHandle(request, response, this.handler, mv);}}}void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {HandlerInterceptor[] interceptors = this.getInterceptors();if (!ObjectUtils.isEmpty(interceptors)) {for(int i = this.interceptorIndex; i >= 0; --i) {HandlerInterceptor interceptor = interceptors[i];try {interceptor.afterCompletion(request, response, this.handler, ex);} catch (Throwable var8) {logger.error("HandlerInterceptor.afterCompletion threw exception", var8);}}}}
}

總結

責任鏈模式是常見的設計模式,各個不同職責的處理器串聯起來,通過一次請求便能夠執行完每個處理器的處理方法。

通過這樣的方式請求的發送者只需發出一次請求同時也不需要知道詳細的鏈路結構;而請求的接送方只關心自己的處理邏輯,自己處理完成之后將請求傳遞給下一個接收者,從而完成自己的任務,這樣便實現了請求發送者和接收者的解耦。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/43758.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/43758.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/43758.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

STM32智能倉庫管理系統教程

目錄 引言環境準備智能倉庫管理系統基礎代碼實現&#xff1a;實現智能倉庫管理系統 4.1 數據采集模塊 4.2 數據處理與控制算法 4.3 通信與網絡系統實現 4.4 用戶界面與數據可視化應用場景&#xff1a;倉庫管理與優化問題解決方案與優化收尾與總結 1. 引言 智能倉庫管理系統通…

藏漢翻譯通作為翻譯軟件的優勢有哪些?

藏漢翻譯通作為一款專業的藏漢雙語翻譯軟件&#xff0c;具有以下優勢&#xff1a; 人工智能技術應用&#xff1a;藏漢翻譯通利用了人工智能翻譯和語音識別合成技術&#xff0c;提供智能藏文翻譯服務。 高準確率&#xff1a;文字識別準確率可達90%&#xff0c;語音識別轉化文字…

蒼穹外賣--導入分類模塊功能代碼

把各層代碼拷貝到所需文件夾下&#xff0c; 進行編譯 在運行 提交和推送倉庫

解鎖AI大模型潛能:預訓練、遷移學習與中間件編程的協同藝術

在人工智能的浩瀚星空中&#xff0c;大型預訓練模型&#xff08;Large Language Models, LLMs&#xff09;猶如璀璨的星辰&#xff0c;引領著技術革新的浪潮。這些模型通過海量數據的滋養&#xff0c;學會了理解語言、生成文本乃至執行復雜任務的能力。然而&#xff0c;要讓這些…

【正點原子i.MX93開發板試用連載體驗】項目計劃和開箱體驗

本文最早發表于電子發燒友&#xff1a;【   】【正點原子i.MX93開發板試用連載體驗】基于深度學習的語音本地控制 - 正點原子學習小組 - 電子技術論壇 - 廣受歡迎的專業電子論壇! (elecfans.com)https://bbs.elecfans.com/jishu_2438354_1_1.html 有一段時間沒有參加電子發…

Pyspider WebUI 未授權訪問致遠程代碼執行漏洞復現

0x01 產品簡介 Pyspider是由國人binux編寫的強大的網絡爬蟲系統,它帶有強大的WebUI(Web用戶界面),為用戶提供了可視化的編寫、調試和管理爬蟲的能力。這一特點使得Pyspider在爬蟲框架中脫穎而出,尤其適合那些希望快速上手并高效開發爬蟲的用戶。允許用戶直接在網頁上編寫…

for in和for of對比

不同點&#xff1a; 時間點不同&#xff1a;for in 在js出現之初就有&#xff0c;for of出現在ES6之后 遍歷的內容不同&#xff1a;for in用于遍歷對象的可枚舉屬性(包括原型鏈上的可枚舉屬性)&#xff0c;for of用于遍歷可迭代對象的值 看個例子 // for in const arr [a,b,…

Linux--線程的控制

目錄 0.前言 1.pthread庫 2.關于控制線程的接口 2.1.創建線程&#xff08;pthread_create&#xff09; 2.2.線程等待&#xff08;pthread_join&#xff09; 代碼示例1&#xff1a; ?編輯 ***一些問題*** 2. 3.創建多線程 3.線程的終止 &#xff08;pthread_exit /…

給數組/對象添加一個(key-value)對象

需要將一個value值前面加上key值&#xff0c;放進數組/對象中 this.$set(res.data[0],type,1) this.$set( target, key, value ) target&#xff1a;要更改的數據源(可以是對象或者數組) key&#xff1a;要更改的具體數據 value &#xff1a;重新賦的值。 結果&#xff1a;…

文華財經盤立方多空變色波段趨勢線指標公式源碼

文華財經盤立方多空變色波段趨勢線指標公式源碼&#xff1a; N1:20; N2:ROUND(N1/2,1); N3:ROUND(SQRT(N1),1); N4:2*EMA2(C,N2)-EMA2(C,N1); 尊重市場:EMA2(N4,N3),COLORRED,LINETHICK2; 尊重市場1:IF(尊重市場<REF(尊重市場,1), 尊重市場,NULL),COLORGREEN,LINETHIC…

C++之List模擬實現

目錄 list的邏輯結構 構造函數 拷貝構造函數 賦值運算符重載 返回迭代器的初始位置 返回迭代器的最終位置 元素的插入 頭插 尾插 刪除元素 頭刪 尾刪 清空整個鏈表 析構函數 正向迭代器 反向迭代器 整體代碼 上期我們學寫了list的基本操作&#xff0c;本期我…

蘇東坡傳-讀書筆記十一

蘇東坡對寫作與風格所表示的意見最為清楚。他說做文章“大略如行云流水&#xff0c;初無定質&#xff0c;但常行于所當行&#xff0c;常止于所不可不止。文理自然&#xff0c;姿態橫生。孔子曰&#xff1a;‘言之不文&#xff0c;行而不遠。’又曰&#xff1a;‘辭達而已矣。’…

【cocos creator】2.4.x實現簡單3d功能,點擊選中,旋轉,材質修改,透明材質

demo下載:(待審核) https://download.csdn.net/download/K86338236/89527924 const {ccclass, property } = cc._decorator;const enum box_color {NORMAL = 0,DASHED_LINE = 1,//虛線TRANSLUCENT = 2,//半透明 }@ccclass export default class main extends cc.Component {…

STC32G/F/8H通用無刷電機驅動板

STC32G/F/8H通用無刷電機驅動板 &#x1f4cc;相關篇《低成本STC32G8K64驅動控制BLDC開源入門學習方案》 ?該驅動板是在上一版的基礎上改版而來。這里的STC32G/F/8H所指的是封裝型號為-LQFP48的STC32G8K64、STC32G12K128、STC32F12K54、STC8H8K64U。是一款兼容有感和無感設計的…

數據結構--樹和二叉樹的一些知識點總結

樹是n個結點的有限集&#xff0c;當n0時&#xff0c;稱為空樹。樹是一種遞歸的數據結構&#xff0c;樹作為一種邏輯結構同時也是一種分層的結構結點的深度是從根開始自頂向下累加&#xff1b;結點的高度是從葉結點自底向上累加由于樹中的分支是有向的&#xff0c;即從雙親指向孩…

【Java算法】二分查找 下

&#x1f525;個人主頁&#xff1a; 中草藥 &#x1f525;專欄&#xff1a;【算法工作坊】算法實戰揭秘 一.山脈數組的峰頂索引 題目鏈接&#xff1a;852.山脈數組的峰頂 ? 算法原理 這段代碼實現了一個查找山峰數組中峰值索引的算法。山峰數組是一個先遞增后遞減的數組&…

玩具營銷是如何拿捏成年人錢包?

好像現在的成年人逐漸熱衷于偏向年輕化&#xff0c;問問題會好奇“尊嘟假嘟”&#xff0c;飯量上的“兒童套餐”&#xff0c;娃娃機前排長隊......而最突出的莫過于各類各式的玩具不斷收割當代年輕人&#xff0c;除去常給大朋友們小朋友們送去玩具福利的“麥、肯”雙門&#xf…

激光干涉儀可以完成哪些測量:全面應用解析

在高端制造領域&#xff0c;精度是衡量產品質量的關鍵指標之一。激光干涉儀作為一項高精度測量技術&#xff0c;其應用廣泛&#xff0c;對于提升產品制造精度具有重要意義。 線性測量&#xff1a;精確定位的基礎 激光干涉儀采用邁克爾遜干涉原理&#xff0c;實現線性測量。該…

AlphaGo 的傳奇故事

文章目錄 一、說明二、AlphaGo 傳奇&#xff08;一&#xff09;&#xff1a;游戲規則三、AlphaGo 傳奇(二)&#xff1a;它是如何運作的&#xff1f;四、AlphaGo 傳奇&#xff08;三&#xff09;&#xff1a;史詩般的戰斗和人工智能的未來 一、說明 1997 年&#xff0c;IBM 的“…

卷積神經網絡之ResNet50遷移學習

數據準備 下載狗與狼分類數據集&#xff0c;數據來自ImageNet&#xff0c;每個分類有大約120張訓練圖像與30張驗證圖像。使用download接口下載數據集&#xff0c;并自動解壓到當前目錄。 全是小狗的圖片 另一邊全是狼的圖片 加載數據集 狼狗數據集提取自ImageNet分類數據集&a…