責任鏈模式 職責鏈模式 Chain of Responsibility Pattern 行為型 設計模式(十七)

責任鏈模式(Chain of Responsibility Pattern)
職責鏈模式
image_5c0e046c_2968

意圖

使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關系
將這些對象連接成一條鏈,并沿著這條鏈傳遞請求,直到有一個對象處理它為止。
責任鏈模式中,每個對象通過持有對下家的引用而鏈接起來,形成一條鏈條,串聯起來多個處理對象。
在責任鏈模式中,請求在鏈上進行傳遞,直到鏈上的某一個對象決定處理此請求。
發出這個請求的客戶端程序并不知道到底是哪一個對象具體的處理了請求
這使得系統可以在不影響客戶端的情況下,動態的重新組織鏈和增加責任
比如類加載機制中的雙親委派模型,類加載器含有父? 類加載器的引用,形成了一個處理鏈
(不過類加載機制的具體行為與責任鏈有出入,會一直委派到最頂級類加載,而不會在中間進行處理然后返回)

解析

責任鏈模式是一種很常見的場景
比如請假,很多公司會根據請假的原因以及請假的時長,將會有不同的審批人
比如采購,對于采購金額的不同,可能需要不同的審批人
思考下請假的過程,可能你經歷過有兩種形式:
形式一:
第一步寫好請假條;
第二步拿給人事,人事說找部門主管簽字
第三步拿請假條給部門主管,部門主管發現請假三天,然后告訴你,一天以上的假期需要老板審批
第四步拿請假條給老板審批
形式二:
第一步寫好請假條交給人事;(人事拿給部門主管,部門主管看情況,如果批不了拿給老板審批)
第二步等待審批;
可能的兩種流程就是上面這樣子的,請假的流程一般就這樣子了,總共有幾級審批,這幾級審批都有誰負責,也不會輕易的變化
再看一個采購審批的例子
示例
以采購為例演示審批流程
抽象處理人角色 處理人擁有姓名屬性,另外定義了抽象的操作方法
package nonechainresponsibility;
public abstract class Handler {
protected String name;
Handler(String name){
this.name = name;
}
public abstract void operation();
}

?

具體的處理人角色 DepartmentManager和Boss?
package nonechainresponsibility;
public class DepartmentManager extends Handler {
public DepartmentManager(String name){
super(name);
}
@Override
public void operation() {
System.out.println("DepartmentManager process..name: "+this.name);
}
}
package nonechainresponsibility;
public class Boss extends Handler {
public Boss(String name) {
super(name);
}@Override
public void operation() {
System.out.println("Boss process..name: " + this.name);
}
}
測試代碼如下,流程很簡單:
如果是金額小于1000元,由部門經理DepartmentManager? 李四審批
否則,將由老總 Boss? 張三? 審批
image_5c0e046c_6677
上面的實例中
測試類Test作為客戶端,也就是相當于采購員
需要自行判斷金額的范圍,然后找對應的審批人進行審批
如果說金額從幾百到幾萬到幾十萬,根據金額分別有十幾個主管負責人進行審批呢?那么審批的邏輯將會變得很復雜
也就是內部將會有更多的選擇邏輯判斷
而且
如果規則變動了呢?你將不得不修改邏輯,進行調整,顯然非常的不利于擴展
即使是新增一個級別的審批,仍舊是需要修改代碼邏輯
另外,如果不同的部門的審批順序略有差異呢?如何應對?
上面的這種處理邏輯的根本問題在于:審批的流程固化在代碼中了
可是你只是個采購員,你希望的只是審批單被批準,你其實并不關心到底是誰審批的,那為什么你要關注于這么多的細節呢?
責任鏈模式就是為了解決這種類似的場景。
一句話概括責任鏈模式:“能搞就搞,搞不了給下一個人,請求發起者不關心誰幫我處理”

代碼示例

處理人角色新增successor 屬性,用于作為下游處理,提供了setSuccessor()方法進行設置?
并且對operation方法進行改變,接受參數(Integer price)
package chainresponsibility;
public abstract class Handler {
protected String name;
Handler(String name){
this.name = name;
}
protected Handler successor;
public void setSuccessor(Handler successor){
this.successor = successor;
}
public abstract void operation(Integer price);
}
部門處理人角色和老板角色同步做出修改
將判斷邏輯移入到處理內部
如果自己不能處理,那么請求下游進行處理(示例比較簡單,所以Boss沒搞)
package chainresponsibility;public class DepartmentManager extends Handler {public DepartmentManager(String name){
super(name);
}
@Override
public void operation(Integer price) {
if(price < 1000){
System.out.println("DepartmentManager process..name: "+this.name);
}else{
successor.operation(price);
}
}
}
package chainresponsibility;
public class Boss extends Handler {public Boss(String name) {
super(name);
}@Override
public void operation(Integer price) {
System.out.println("Boss process..name: " + this.name);
}
}
測試代碼
package chainresponsibility;
public class Test {
public static void main(String[] args){
/*
* 動態生成鏈條
* */
Handler DmHandler = new DepartmentManager("李四");
Handler BossHandler = new Boss("張三");
DmHandler.setSuccessor(BossHandler);/*
* 調用處理鏈的一個起始端點
* */
DmHandler.operation(600);
DmHandler.operation(6000);
}
}

?

image_5c0e046c_872
重構后的代碼邏輯沒有發生變化---仍舊是處理請求
但是通過引入successor 屬性,以及setSuccessor()方法,可以將下游處理者串聯起來
擁有了下游的引用,如果處理不了就可以將請求向下傳遞
因為每個處理者都需要獨立面對請求,所以將邏輯內置,也就是條件以參數的形式傳遞
通過指向下游處理對象的引用,形成了一條鏈,每次請求只需要請求開始端點位置的對象即可
如果無法處理,會自動請求下游的對象進行處理,客戶端不需要關注
而且,通過引用可以在運行期間動態的組織職責鏈,比如不同部門處理層級不一樣的問題就可以輕易解決
如果增加新的審批層級,只需要新增審批類,并且在創建責任鏈的時候,將新增的審批類添加進去即可
客戶端并不需要發生變動
上面的示例簡單的演示了職責鏈模式的演變過程
簡單說就是每個人職責清晰的獨立劃分開來,然后一個模塊負責組裝生成責任鏈?
客戶端將請求發送給責任鏈的起始點即可

結構

image_5c0e046c_6dbf
抽象處理者角色Handler
定義一個處理請求的接口
Handler角色知道“下一個處理者”是誰,如果自己無法處理請求,他會將請求轉發給“下一個處理者”?
具體的處理者角色ConcreteHandler
處理請求的具體角色,比如上面示例中的DepartmentManager
客戶端角色Client
Client角色向組裝好的責任鏈的第一個ConcreteHandler發起請求

通過責任鏈模式弱化了請求發起者與請求處理者的聯系
對于請求者來說,責任鏈上的所有對象就是一個請求處理者,到底具體到哪個類進行出力,請求者并不關心
不存在“某個請求必須要誰處理”這種明確的指向關系,請求者不清楚
專注于自己的工作
每個處理業務的對象都更加專注于自己的工作,如果自己無法處理,那么交給其他更專業的人
這樣則能保障任務能夠快速高效的完成
責任鏈模式并不創建責任鏈,由系統的其他部分負責創建
示例為了簡單所以在測試主函數中一并創建,應該由系統其他部分進行創建,將責任鏈的連接邏輯與使用解耦
動態改變職責鏈
引用是組合的形式,可以在運行時動態的設定
上面說到責任鏈由系統的其他部分進行創建,他可以動態的完成責任鏈的創建

分類

責任鏈模式分為純粹的責任鏈模式和不純粹的責任鏈模式
純粹的責任鏈模式要求責任鏈中的對象,也就是具體的處理者只能在兩個行為中選擇一個
也就是要么承擔責任,要么責任轉交給下家
不允許出現某一個具體的處理者對象承擔了一部分責任之后又把責任向下傳遞。
而通常情況下,我們的實際使用的責任鏈模式很難純粹,基本都會摻雜一些處理邏輯
其實這種命名與否的爭論對于使用模式毫無意義,重點在于解決問題?
黑貓白貓抓到老鼠就是好貓

總結

如果你的系統中已經存在了一個由多個處理者對象組成的請求處理序列
那么你就可以考慮將這個請求處理轉換為責任鏈模式
如果有多于一個處理者對象會處理一個請求,但是事先卻并不知道到底誰來處理
這個處理者對象是動態確定的,比如新來一個采購員,他還不熟悉公司規則,不確定到底誰來負責審批他的這個單子
責任鏈顯著的特點就是將請求和處理者進行分離,請求者可以不知道具體是誰處理了請求,將請求與處理進行了解耦,提高了系統的靈活性?
具體的處理者可能還與責任鏈的組成順序有很大的關系,通過選擇某些處理者組成鏈,以及設置順序,增加了極大的靈活性
責任鏈模式所有的請求都通過責任鏈進行處理,如果鏈比較長,而且需求總是在后端進行處理,勢必會引入一些性能問題
而且,客戶端不知道具體誰處理的,你也不知道,環節較多,調試時也會不方便
而且還需要控制節點的數量,要避免超長鏈的情況,那樣這條鏈將會變成一種負擔,這種會破壞系統的性能??
而且還需要注意,如果一個請求從頭走到尾是否一定會有對象對他進行處理?如果沒有被處理也可能是因為沒有正確的配置責任鏈而導致的
如果鏈接生成的有問題,比如環形,并且也沒有設置次數限制,豈不是死循環?這些問題都需要在運用時考慮到
對于責任鏈一句話總結:如果一個請求,可能會被多個處理者中的一個處理,考慮責任鏈模式
原文地址:責任鏈模式 職責鏈模式 Chain of Responsibility Pattern 行為型 設計模式(十七)

?

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

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

相關文章

YOLOv7 在 ML.NET 中使用 ONNX 檢測對象

本文介紹如何在 ML.NET 中使用 YOLOv7 的 ONNX 模型來檢測圖像中的對象。什么是 YOLOYOLO&#xff08;You Only Look Once&#xff09;是一種先進的實時目標檢測系統。它是一個在COCO數據集上預訓練的物體檢測架構和模型系列&#xff0c;其版本也是在不斷優化更新。2022年7月&a…

Vue中render: h = h(App)的含義

原文地址&#xff1a;Explanation for render: h > h(App) please 翻譯如下&#xff1a; render: h > h(App) 是下面內容的縮寫&#xff1a; render: function (createElement) {return createElement(App); }進一步縮寫為(ES6 語法)&#xff1a; render (createElem…

NppFTP小插件的使用

大家在Linux系統中配置運行環境時&#xff0c;一定會遇到相關配置文件的修改&#xff0c;雖說在Linux系統中可以使用vi,vim的命令進行文本編輯&#xff0c;但是操作起來還是沒有在Windows系統中用的爽&#xff0c;特別是操作大文本量的文件時。Notepad里提供了一個小插件&#…

『實戰』使用Excel催化劑二維碼功能批量生成帶不同圖案二維碼。

熟悉Excel催化劑的老讀者都知道&#xff0c;每逢圖書大促&#xff0c;筆者都會向出版社申請優惠碼優惠券來惠及廣大粉絲。當然公眾號上幫出版社推薦圖書&#xff0c;會有傭金回報&#xff0c;這也是筆者唯一能接受的推廣方式。公眾號自創立以來&#xff0c;沒有接過軟文&#x…

springboot ElasticSearch 簡單的全文檢索高亮

前陣子和張三豐聊天提到了es。這次正好有機會學習并使用 首先引入依賴 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> 配置文件 spring.data.…

JavaScriptSerializer類 對象序列化為JSON,JSON反序列化為對象

JavaScriptSerializer 類由異步通信層內部使用&#xff0c;用于序列化和反序列化在瀏覽器和 Web 服務器之間傳遞的數據。說白了就是能夠直接將一個C#對象傳送到前臺頁面成為javascript對象。要添加System.Web.Extensions.dll的引用。該類位于System.Web.Script.Serialization命…

nodejs 實踐:express 最佳實踐(六) express 自省獲得所有的路由

nodejs 實踐&#xff1a;express 最佳實踐(六) express 自省獲得所有的路由 某些情況下&#xff0c;你需要知道你的應用有多少路由&#xff0c;這在 express 中沒有方法可以。因此我這邊曲線了一下&#xff0c;做成了一個函數進行處理。遍歷所有的方法進行處理。 代碼 const _ …

使用vue組件搭建網頁應用

使用vue組件搭建網頁應用搭建開發環境開發組件搭建開發環境 搭建一個 vue 項目最快的方式就是使用 vue cli 腳手架進行初始化&#xff0c;包含了所有完整的依賴及開發配置。 首先全局安裝 vue cli&#xff0c;打開 cmd 命令提示符 或者 power shell&#xff0c;輸入以下命令&…

重新整理 .net core 實踐篇 —linux上排查問題實用工具 [外篇]

前言介紹下面幾個工具:Lldbcreatedumpdotnet-dumpdotnet-gcdumpdotnet-symbolProcdump該文的前置篇為:https://www.cnblogs.com/aoximin/p/16839812.html獻給初學者&#xff0c;這篇就只介紹下看下日志和lldb&#xff0c;畢竟東西太多了。正文我以官網的例子作為演示&#xff1…

Office 365離線安裝

Office 365除了可以在線安裝外&#xff0c;還可以進行離線安裝&#xff0c;但激活還是需要連接互聯網的喲首先下載Office部署工具https://www.microsoft.com/en-us/download/details.aspx?id49117 下載文件后&#xff0c;運行自解壓縮可執行文件&#xff0c;其中包含 Office 部…

reduceByKey和groupByKey區別與用法

2019獨角獸企業重金招聘Python工程師標準>>> 在Spar看中&#xff0c;我們知道一切的操作都是基于RDD的。在使用中&#xff0c;RDD有一種非常特殊也是非常實用的format——pair RDD&#xff0c;即RDD的每一行是&#xff08;key, value&#xff09;的格式。這種格式很…

python自動化測試-D6-學習筆記之一(常用模塊補充datetime模塊)

# datetime 模塊import datetimeprint(datetime.datetime.today()) #當前日期&#xff0c;到秒 打印結果&#xff1a;2018-01-21 10:23:46.034410print(datetime.datetime.now()) # 當前日期&#xff0c;到秒 打印結果&#xff1a;2018-01-21 10:23:46.034410print(datetime.d…

Vue如何在data中正確引入圖片路徑

方法一&#xff1a;將圖片資源放入項目 /static 目錄下&#xff0c;使用絕對或相對路徑引用即可 // 文件結構 |-- src | |-- components | | |-- banner.vue |-- static | |-- images | | |-- pic.jpg<template><div id"banner"><img :s…

軟件工程的第一性原理丨SmartIDE

作者&#xff1a;徐磊原文地址&#xff1a;https://smartide.cn/zh/blog/2022-1022-software-engineering/徐磊英捷創軟科技&#xff08;北京&#xff09;有限公司創始?/?席架構師 / CEO / SmartIDE開源項?創始?。微軟最有價值專家MVP&#xff0c;微軟區域技術總監&#xf…

排序算法之快速排序詳解

一、算法介紹 快速排序&#xff1a;快速排序的基本思想是通過一次排序將等待的記錄分成兩個獨立的部分&#xff0c;其中一部分記錄的關鍵字小于另一部分的關鍵字。C部分的快速排序一直持續到整個序列被排序。 任取一個元素 (如第一個) 為中心提出所有小于它的元素&#xff0c;并…

openstack 中國聯盟公開課參會總結

主流趨勢 1. openstack defcore 互操作性認證。打通不同的openstack 廠商之間的連接2. 首批OpenStack管理員認證(COA)將于2016年進行3. 混合云應用廣泛 Cloud Broker,cascading openstack 云連接器4. DevOps5. 虛擬桌面6. Storage 方面&#xff0c;Ceph和Glusterfs 7. Network…

bzoj1088[SCOI2005]掃雷Mine

1088: [SCOI2005]掃雷Mine Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4284 Solved: 2552[Submit][Status][Discuss]Description 相信大家都玩過掃雷的游戲。那是在一個n*m的矩陣里面有一些雷&#xff0c;要你根據一些信息找出雷來。萬圣節到了&#xff0c;“余”人國流…

Re:從零開始的Vue項目搭建

Re&#xff1a;從零開始的Vue項目搭建初始的終結與結束的開始Nodejs項目的簡單測試從零開始webpack開發模式webpack編譯打包后記初始的終結與結束的開始 最開始接觸vue項目搭建是從vue-cli開始&#xff0c;模板式操作&#xff0c;一鍵搞定&#xff0c;幾乎可以無縫進入代碼開發…

在數據庫插入帶小數點數據的問題

想在mysql插入以下數據設計表的時候沒有注意,之前都用的int,這次換成了double,但是插入第一條3.50的時候數據庫顯示為:查了之后知道是設計表的時候沒有注意小數點的設置轉載于:https://juejin.im/post/5c0f61bb6fb9a049ea38cbe9

oracle 11g 創建 job 20

15-10-19 23:48:04分類&#xff1a; Oracle--創建一次執行的匿名塊任務&#xff0c;成功調用一次后job消失BEGIN DBMS_SCHEDULER.CREATE_JOB ( job_name > my_new_job2, job_type > PLSQL_BLOCK, job_action &g…