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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...