c#中責任鏈模式詳解

来源:https://www.cnblogs.com/mingnianjiehunba/archive/2023/11/15/17831063.html
-Advertisement-
Play Games

本文介紹了結構型設計模式中的代理設計模式,講解了靜態代理、JDK的動態代理和cglib的動態代理,並用代碼進行演示。 ...


基本介紹:

  “責任鏈”顧名思義,是指一個需要負責處理請求的鏈條

  每個鏈條節點都是一個單獨的責任者,由責任者自己決定是否處理請求或交給下一個節點

  在設計模式中的解釋則為:為請求創建了一個接收者對象的鏈。適用於有多個對象可以處理同一個請求,但具體由哪個對象處理則在運行時動態決定的情況。

  俗話說起來就是一群領導組成了一個上下級鏈路關係,每個領導的職責各不相同,老百姓辦事情的時候肯定沒辦法知道該找哪個領導。

  這個時候就可以把需要辦的事情交給接待人員,由接待人員自行判斷是不是可以處理或者交給上級處理,至於是誰給我負責,那我這個小老百姓並不關心,只要辦了就可以了。

  老百姓辦的事情就是請求,接待人員和領導群組成的集合就是責任鏈,每個領導負責自己的職責,至於最後是誰負責,那就根據具體事情一級一級的傳遞動態決定。

  這麼做的好處也顯而易見,我的請求可以是任意的,具體要不要解決由誰解決,都交給責任鏈自己去判斷。

舉例說明:

  公司的請假系統,當一個員工提交請假申請時,根據請假天數和職位的不同,需要由不同等級的領導審批。

  項目組長》部門經理》總經理》董事長》董事會就組成了一個責任鏈。

  普通員工和項目組長都是請假1天,但是由誰負責審批,交給責任鏈就可以了,由責任鏈自己決定由誰去審批。

  比如普通員工請假1天,只需要交給項目組長審批就可以。但如果是項目組長請假1天,需要交給部門經理審批。

  這種直接有單個責任人負責處理的稱為純的職責鏈模式

  一個請求必須被某一個處理者對象所接收,且一個具體處理者對某個請求的處理只能採用以下兩種行為之一:自己處理或把責任提交給上級處理。

 

  如果普通員工請假1個月,項目組長一般沒有直接審批的許可權,需要先由項目組成初步審批,再由項目組長提交給部門經理進行審批。

  這種單個責任人負責部分責任的情況稱為不純的職責鏈模式

  允許出現某一個具體處理者對象在承擔了請求的一部分責任後又將剩餘的責任傳給上級的情況,且一個請求可以最終不被任何接收端對象所接收。

 

  在一個純的職責鏈模式裡面,一個請求必須被某一個處理者對象所接收;

  在一個不純的職責鏈模式裡面,一個請求可以被多個處理者對象所處理或最終不被任何接收端對象所接收。

基本結構:

  抽象處理者角色:它定義一個處理請求的介面或抽象類,由於不同的具體處理者處理請求的方式不一樣,因此在其中定義一個抽象的處理方法。同時該類需要維持一個指向上級的引用,通過該引用,處理者可以連成一條線。

  具體處理者角色:繼承自抽象類,具體實現處理方法,在處理方法中進行處理或不滿足職責向上級轉發請求。

  客戶端角色:負責鏈路組合順序。

  請求者角色:構建請求對象。一般通過參數方式註入到具體處理類中。

優缺點:

  優點

  • 降低了對象之間的耦合度。該模式使得一個對象無須知道到底是哪一個對象處理其請求以及鏈的結構,發送者和接收者也無須擁有對方的明確信息。
  • 增強了系統的可擴展性。可以根據需要增加新的請求處理類,滿足開閉原則。
  • 增強了給對象指派職責的靈活性。當工作流程發生變化,可以動態地改變鏈內的成員或者調動它們的次序,也可動態地新增或者刪除責任。
  • 責任鏈簡化了對象之間的連接。每個對象只需保持一個指向其後繼者的引用,不需保持其他所有處理者的引用,這避免了使用眾多的 if 或者 if···else 語句。
  • 責任分擔。每個類只需要處理自己該處理的工作,不該處理的傳遞給下一個對象完成,明確各類的責任範圍,符合類的單一職責原則。

  缺點

  • 不能保證每個請求一定被處理。由於一個請求沒有明確的接收者,所以不能保證它一定會被處理,該請求可能一直傳到鏈的末端都得不到處理。
  • 對比較長的職責鏈,請求的處理可能涉及多個處理對象,系統性能將受到一定影響。
  • 職責鏈建立的合理性要靠客戶端來保證,增加了客戶端的複雜性,可能會由於職責鏈的錯誤設置而導致系統出錯,如可能會造成迴圈調用。

具體實例:

  1     /// <summary>
  2     /// 請假條類
  3     /// </summary>
  4     public class LeaveRequest
  5     {
  6         //請假人
  7         public string Name { get; set; }
  8 
  9         //請假天數
 10         public int RestDaySum { get; set; }
 11 
 12         //職業等級
 13         public int Grade { get; set; }
 14 
 15         //構造函數中初始化請假信息
 16         public LeaveRequest(string strName, int iRestDaySum, int iGrade)
 17         {
 18             Name = strName;
 19             RestDaySum = iRestDaySum;
 20             Grade = iGrade;
 21         }
 22     }
 23 
 24     /// <summary>
 25     /// 抽象類
 26     /// </summary>
 27     public abstract class Approver
 28     {
 29         public Approver()
 30         {
 31             SetGrade();
 32         }
 33         //下一責任人引用
 34         protected Approver _Approver;
 35 
 36         //職業等級
 37         protected int Grade { get; set; }
 38 
 39         //設置下一個審批人,用來形成鏈路
 40         public void SetNextApprover(Approver approver)
 41         {
 42             this._Approver = approver;
 43         }
 44 
 45         //設置職業等級
 46         public abstract void SetGrade();
 47 
 48         //處理請求
 49         public abstract void ProcessRequest(LeaveRequest leaveRequest);
 50     }
 51 
 52     /// <summary>
 53     /// 具體實現類---組長
 54     /// </summary>
 55     public class GroupLeader : Approver
 56     {
 57         public override void ProcessRequest(LeaveRequest leaveRequest)
 58         {
 59             if (leaveRequest.Grade >= this.Grade)
 60             {
 61                 Console.WriteLine(leaveRequest.Name + "的請假條,組長無權處置!交由上級審核!");
 62                 _Approver.ProcessRequest(leaveRequest);
 63             }
 64             else
 65             {
 66                 if (leaveRequest.RestDaySum > 3)
 67                 {
 68                     Console.WriteLine(leaveRequest.Name + "的請假條,請假天數超出組長的職權,交由上級審核!");
 69                     _Approver.ProcessRequest(leaveRequest);
 70                 }
 71                 else
 72                 {
 73                     Console.WriteLine(leaveRequest.Name + "的請假條,經由組長審核通過,批准休假。");
 74                 }
 75             }
 76         }
 77 
 78         public override void SetGrade()
 79         {
 80             this.Grade = 2;
 81         }
 82     }
 83 
 84     /// <summary>
 85     /// 具體實現類---部門經理
 86     /// </summary>
 87     public class Manager : Approver
 88     {
 89         public override void ProcessRequest(LeaveRequest leaveRequest)
 90         {
 91             if (leaveRequest.Grade >= this.Grade)
 92             {
 93                 Console.WriteLine(leaveRequest.Name + "的請假條,部門經理無權處置!交由上級審核!");
 94                 _Approver.ProcessRequest(leaveRequest);
 95             }
 96             else
 97             {
 98                 if (leaveRequest.RestDaySum > 7)
 99                 {
100                     Console.WriteLine(leaveRequest.Name + "的請假條,請假天數超出部門經理的職權,交由上級審核!");
101                     _Approver.ProcessRequest(leaveRequest);
102                 }
103                 else
104                 {
105                     Console.WriteLine(leaveRequest.Name + "的請假條,經由部門經理審核通過,批准休假。");
106                 }
107             }
108         }
109 
110         public override void SetGrade()
111         {
112             this.Grade = 3;
113         }
114     }
115 
116     /// <summary>
117     /// 具體實現類---總經理
118     /// </summary>
119     public class GeneralManager : Approver
120     {
121         public override void ProcessRequest(LeaveRequest leaveRequest)
122         {
123             if (leaveRequest.Grade >= this.Grade)
124             {
125                 Console.WriteLine(leaveRequest.Name + "的請假條,總經理無權處置!交由上級審核!");
126                 _Approver.ProcessRequest(leaveRequest);
127             }
128             else
129             {
130                 if (leaveRequest.RestDaySum > 30)
131                 {
132                     Console.WriteLine(leaveRequest.Name + "的請假條,請假天數超出總經理的職權,交由上級審核!");
133                     _Approver.ProcessRequest(leaveRequest);
134                 }
135                 else
136                 {
137                     Console.WriteLine(leaveRequest.Name + "的請假條,經由總經理審核通過,批准休假。");
138                 }
139             }
140         }
141 
142         public override void SetGrade()
143         {
144             this.Grade = 4;
145         }
146     }
147 
148     /// <summary>
149     /// 客戶端
150     /// </summary>
151     class Client
152     {
153         static void Main(string[] args)
154         {
155             //創建組長責任人
156             Approver groupLeader = new GroupLeader();
157             //創建部門經理責任人
158             Approver manager = new Manager();
159             //創建總經理責任人
160             Approver generalManager = new GeneralManager();
161 
162             //設置組長的上級為部門經理
163             groupLeader.SetNextApprover(manager);
164             //設置部門經理的上級為總經理
165             manager.SetNextApprover(generalManager);
166 
167             //通過以上操作構建了責任鏈
168 
169             //創建請求---請假條---普通職員張三請假3天
170             LeaveRequest leaveRequest = new LeaveRequest("張三", 3, 1);
171             //將請假條交給責任鏈起始端
172             groupLeader.ProcessRequest(leaveRequest);
173             Console.WriteLine("\r\n");
174 
175             //創建請求---請假條---部門經理李四請假3天
176             leaveRequest = new LeaveRequest("李四", 3, 3);
177             //將請假條交給責任鏈起始端
178             groupLeader.ProcessRequest(leaveRequest);
179             Console.WriteLine("\r\n");
180 
181 
182             //創建請求---請假條---普通職員小王請假7天
183             leaveRequest = new LeaveRequest("小王", 7, 1);
184             //將請假條交給責任鏈起始端
185             groupLeader.ProcessRequest(leaveRequest);
186             Console.WriteLine("\r\n");
187 
188             //如果知道鏈條的初始端可以不用從最開始端進行
189             //創建請求---請假條---組長老劉請假3天
190             leaveRequest = new LeaveRequest("老劉", 3, 2);
191             //將請假條交給責任鏈中的部門經理
192             manager.ProcessRequest(leaveRequest);
193             Console.WriteLine("\r\n");
194 
195             Console.ReadKey();
196         }
197     }

總結:

  責任鏈模式屬於行為型模式。它使多個對象都有機會處理請求,從而避免發送者和接受者之間的耦合關係。將這個對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個對象處理它為止。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本文利用向量的點積和叉積來判斷點是否線上段上。 基礎知識補充 從零開始的高中數學——向量、向量的點積、帶你一次搞懂點積(內積)、叉積(外積)、Unity游戲開發——向量運算(點乘和叉乘 說明 點積可以用來判斷兩個向量的夾角,如果這個夾角是0或者180度,說明這個點在直線上; 叉積可以用來判斷一個點到 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、故事的開始 最近產品又開始整活了,本來是毫無壓力的一周,可以小摸一下魚的,但是突然有一天跟我說要做一個在網頁端截屏的功能。 作為一個工作多年的前端,早已學會了儘可能避開麻煩的需求,只做增刪改查就行! 我立馬開始了我的反駁,我的理由是市 ...
  • 本篇文章從數據中心,事件中心如何協議工作、不依賴環境對vue2.x、vue3.x都可以支持、投產頁面問題定位三個方面進行分析。 ...
  • 介面數據類型與表單提交數據類型,在大多數情況下,大部分屬性的類型是相同的,但很少能做到完全統一。我在之前的工作中經常為了方便,直接將介面數據類型復用為表單內數據類型,在遇到屬性類型不一致的情況時會使用any強制忽略類型錯誤。後來經過自省與思考,這種工作模式會引起各種隱藏bug,一定有更好的工程解決方... ...
  • 1、提示 由於國內註冊 https://api.openai.com 比較麻煩,直接購買的第三方介面和key 淘寶購買,幾塊錢1個月 3、自己娛樂夠用 2、前端框架 Vant 移動端使用 axios 3、創建攔截器,api/request.js /* * @Descripttion: 文件說明 * ...
  • 跨域這兩個字就像一塊狗皮膏藥一樣黏在每一個前端開發者身上,無論你在工作上或者面試中無可避免會遇到這個問題。如果在網上搜索跨域問題,會出現許許多多方案,這些方案有好有壞,但是對於闡述跨域的原理和在什麼情況下需要用什麼方案,缺少系統性的說明。大家在工作中可能因為大佬們已經配置好了,不會產生跨域,但是作為... ...
  • 我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。 本文作者:奇銘 前言 目前數棧的多個產品中都支持線上編輯 SQL 來生成對應的任務。比如離線開發產品和實時開發產品。在使用 MonacoEditor 為編輯器的基礎上, ...
  • 需求落地分散式應用服務 將需求轉化為分散式應用服務的過程可以按照以下步驟進行: 理解需求:首先,你需要仔細閱讀和理解業務需求。與相關的利益相關者(如業務分析師、產品經理等)進行溝通,確保你對需求的理解是準確的。 設計架構:根據需求,設計一個適合的分散式應用架構。這包括確定應用的組件和模塊,以及它們之 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...