職責鏈模式(23)

来源:http://www.cnblogs.com/xiaomowang/archive/2017/02/15/6400478.html
-Advertisement-
Play Games

今天我們來講一下職責鏈模式。首先我們來模擬一下下麵這個場景。 一、案例 在公司,我們需要向領導請假,向領導申請加薪,不同級別的領導會做出相應的批示。下麵我們用簡單的控制台應用程式來模擬一下這個案例。 客戶端調用: 好,下麵我們來分析一下上述代碼,看看有什麼問題和缺陷。 ①:GetResult這個方法 ...


今天我們來講一下職責鏈模式。首先我們來模擬一下下麵這個場景。

一、案例

在公司,我們需要向領導請假,向領導申請加薪,不同級別的領導會做出相應的批示。下麵我們用簡單的控制台應用程式來模擬一下這個案例。

  1     /// <summary>
  2     /// 申請類
  3     /// </summary>
  4     class Request
  5     {
  6         //申請類別
  7         private string requestType;
  8         public string RequestType
  9         {
 10             get
 11             {
 12                 return requestType;
 13             }
 14 
 15             set
 16             {
 17                 requestType = value;
 18             }
 19         }
 20         //申請內容
 21         private string requestContent;
 22         public string RequestContent
 23         {
 24             get
 25             {
 26                 return requestContent;
 27             }
 28 
 29             set
 30             {
 31                 requestContent = value;
 32             }
 33         }
 34         //數量
 35         private int number;
 36         public int Number
 37         {
 38             get
 39             {
 40                 return number;
 41             }
 42 
 43             set
 44             {
 45                 number = value;
 46             }
 47         }
 48     }
 49 
 50     /// <summary>
 51     /// 管理者類
 52     /// </summary>
 53     class Manager
 54     {
 55         protected string name;
 56 
 57         public Manager(string name)
 58         {
 59             this.name = name;
 60         }
 61         //得到結果
 62         public void GetResult(string managerLevel, Request request)
 63         {
 64             //比較長的方法,多條的分支,這些其實都是代碼壞味道
 65             if (managerLevel == "經理")
 66             {
 67                 if (request.RequestType == "請假" && request.Number <= 2)
 68                 {
 69                     Console.WriteLine($"{name}:{request.RequestContent} 數量{request.Number} 被批准");
 70                 }
 71                 else
 72                 {
 73                     Console.WriteLine($"{name}:{request.RequestContent} 數量{request.Number} 我無權處理");
 74                 }
 75             }
 76             else if (managerLevel == "總監")
 77             {
 78                 if (request.RequestType == "請假" && request.Number <= 5)
 79                 {
 80                     Console.WriteLine($"{name}:{request.RequestContent} 數量{request.Number} 被批准");
 81                 }
 82                 else
 83                 {
 84                     Console.WriteLine($"{name}:{request.RequestContent} 數量{request.Number} 我無權處理");
 85                 }
 86             }
 87             else if (managerLevel=="總經理")
 88             {
 89                 if (request.RequestType=="請假")
 90                 {
 91                     Console.WriteLine($"{name}:{request.RequestContent} 數量{request.Number} 被批准");
 92                 }
 93                 else if (request.RequestType=="加薪"&&request.Number<=500)
 94                 {
 95                     Console.WriteLine($"{name}:{request.RequestContent} 數量{request.Number} 被批准");
 96                 }
 97                 else if (request.RequestType == "加薪" && request.Number > 500)
 98                 {
 99                     Console.WriteLine($"{name}:{request.RequestContent} 數量{request.Number} 再說吧");
100                 }
101             }
102         }
103     }

客戶端調用:

 1         public static void Main()
 2         {
 3             //三個管理者
 4             Manager jinli = new Manager("金立");
 5             Manager zongjian = new Manager("宗劍");
 6             Manager zhongjingli = new Manager("鐘精勵");
 7 
 8             //小魔王請求加薪1000
 9             Request request = new Request();
10             request.RequestType = "加薪";
11             request.RequestContent = "小魔王請求加薪";
12             request.Number = 1000;
13 
14             //不同級別對此請求做判斷和處理
15             jinli.GetResult("經理", request);
16             zongjian.GetResult("總監", request);
17             zhongjingli.GetResult("總經理", request);
18 
19             //請假3天
20             Request request2 = new Request();
21             request2.RequestType = "請假";
22             request2.RequestContent = "小魔王請假";
23             request2.Number = 3;
24 
25             // 不同級別對此請求做判斷和處理
26             jinli.GetResult("經理", request2);
27             zongjian.GetResult("總監", request2);
28             zhongjingli.GetResult("總經理", request2);
29 
30             Console.ReadKey();
31         }

好,下麵我們來分析一下上述代碼,看看有什麼問題和缺陷。

①:GetResult這個方法太長,分支太多,讓人感覺很不舒服,代碼壞了味道。違背了單一職責的原則

②:如果還有其他的管理級別的管理者,那麼,就需要修改Manager類,違背了開放-封閉原則。

我們如何才能不僅實現功能,而且還能解決上述的問題呢?下麵就是我們要講的職責鏈模式了。

什麼是職責鏈模式呢?職責鏈模式:使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這個對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個對象處理它為止。

我們來看一下它的代碼結構

 1     //定義一個處理請示的介面
 2     abstract class Handler
 3     {
 4         protected Handler successor;
 5         //設置繼任者
 6         public void SetSuccessor(Handler successor)
 7         {
 8             this.successor = successor;
 9         }
10         //處理請求的抽象方法
11         public abstract void HandleRequest(int request);
12     }
13 
14     //具體處理者類,處理它所負責的請求,可訪問它的後繼者,如果可處理請求就處理它,
15     //否則,將該請求轉發給它的後繼者。
16     class ConcreteHandler1 : Handler
17     {
18         public override void HandleRequest(int request)
19         {
20             if (request >= 0 && request < 10)
21             {
22                 Console.WriteLine($"{this.GetType().Name}{request}");
23             }
24             else if (successor != null)
25             {
26                 //轉移到下一位去處理
27                 successor.HandleRequest(request);
28             }
29         }
30     }
31     class ConcreteHandler2 : Handler
32     {
33         public override void HandleRequest(int request)
34         {
35             if (request >= 10)
36             {
37                 Console.WriteLine($"{this.GetType().Name}{request}");
38             }
39             else if (successor != null)
40             {
41                 //轉移到下一位去處理
42                 successor.HandleRequest(request);
43             }
44         }
45     }

客戶端

 1         public static void Main()
 2         {
 3             Handler h1 = new ConcreteHandler1();
 4             Handler h2 = new ConcreteHandler2();
 5             h1.SetSuccessor(h2);
 6 
 7             int[] requests = {2, 5, 14, 22};
 8             foreach (int request in requests)
 9             {
10                 h1.HandleRequest(request);
11             }
12             Console.ReadKey();
13         }

這當中,最關鍵的是當客戶提交一個請求時,請求是沿著鏈傳遞直至有一個ConcreteHandler對象負責處理它。接收者和發送者都沒有對方的明確消息,且鏈中的對象自己也並不知道鏈的結構。結果是職責鏈可簡化對象的相互連接,他們僅需保持一個指向其後繼者的引用,而不需要保持它所有的候選接受著的引用。

下麵,我們用職責鏈模式將我們案例重構一下。

  1     /// <summary>
  2     /// 申請類
  3     /// </summary>
  4     class Request
  5     {
  6         //申請類別
  7         private string requestType;
  8         public string RequestType
  9         {
 10             get
 11             {
 12                 return requestType;
 13             }
 14 
 15             set
 16             {
 17                 requestType = value;
 18             }
 19         }
 20         //申請內容
 21         private string requestContent;
 22         public string RequestContent
 23         {
 24             get
 25             {
 26                 return requestContent;
 27             }
 28 
 29             set
 30             {
 31                 requestContent = value;
 32             }
 33         }
 34         //數量
 35         private int number;
 36         public int Number
 37         {
 38             get
 39             {
 40                 return number;
 41             }
 42 
 43             set
 44             {
 45                 number = value;
 46             }
 47         }
 48     }   
 49     //管理者
 50     abstract class Manager
 51     {
 52         protected string name;
 53         //管理者的上級
 54         protected Manager superior;
 55 
 56         public Manager(string name)
 57         {
 58             this.name = name;
 59         }
 60         //設置管理者的上級
 61         public void SetSuperior(Manager superior)
 62         {
 63             this.superior = superior;
 64         }
 65 
 66         abstract public void RequestApplications(Request request);
 67     }
 68     //經理
 69     class CommonManager:Manager
 70     {
 71         public CommonManager(string name) : base(name)
 72         {
 73         }
 74 
 75         public override void RequestApplications(Request request)
 76         {
 77             if (request.RequestType == "請假" && request.Number <= 2)
 78             {
 79                 Console.WriteLine($"{name}{request.RequestContent}{request.Number}");
 80             }
 81             else
 82             {
 83                 //其餘的申請都需轉到上級
 84                 if (superior!=null)
 85                 {
 86                     superior.RequestApplications(request);
 87                 }
 88             }
 89         }
 90     }
 91     //總監
 92     class Majordomo : Manager
 93     {
 94         public Majordomo(string name) : base(name)
 95         {
 96         }
 97 
 98         public override void RequestApplications(Request request)
 99         {
100             if (request.RequestType == "請假" && request.Number <= 5)
101             {
102                 Console.WriteLine($"{name}{request.RequestContent}{request.Number}");
103             }
104             else
105             {
106                 //其餘的申請都需轉到上級
107                 if (superior != null)
108                 {
109                     superior.RequestApplications(request);
110                 }
111             }
112         }
113     }
114     //總經理
115     class GeneralManager : Manager
116     {
117         public GeneralManager(string name) : base(name)
118         {
119         }
120 
121         public override void RequestApplications(Request request)
122         {
123             if (request.RequestType == "請假" )
124             {
125                 Console.WriteLine($"{name}{request.RequestContent}{request.Number}");
126             }
127             else if (request.RequestType=="加薪"&&request.Number<=500)
128             {
129                 Console.WriteLine("批准");
130             }
131             else
132             {
133                 Console.WriteLine("再說吧");
134             }
135         }
136     }

客戶端:

 1         public static void Main()
 2         {
 3             CommonManager jinli = new CommonManager("金立");
 4             Majordomo zongjian = new Majordomo("宗劍");
 5             GeneralManager zhongjingli = new GeneralManager("鐘精勵");
 6             //根據實際需求設置上級
 7             jinli.SetSuperior(zongjian);
 8             zongjian.SetSuperior(zhongjingli);
 9 
10             //客戶端的申請都是由‘經理’發起,但實際上誰來決策由具體的管理類來處理,客戶端不知道。
11             Request request = new Request();
12             request.RequestType = "請假";
13             request.RequestContent = "小魔王請假";
14             request.Number = 1;
15             jinli.RequestApplications(request);
16 
17             Request request2 = new Request();
18             request2.RequestType = "請假";
19             request2.RequestContent = "小魔王請假";
20             request2.Number = 4;
21             jinli.RequestApplications(request2);
22 
23             Request request3 = new Request();
24             request2.RequestType = "加薪";
25             request2.RequestContent = "小魔王加薪";
26             request2.Number = 1000;
27             jinli.RequestApplications(request2);
28 
29             Console.ReadKey();
30         }

好了,職責鏈模式就講到這裡了,下一篇我們講 中介者模式


 本系列將持續更新,喜歡的小伙伴可以點一下關註和推薦,謝謝大家的支持


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

-Advertisement-
Play Games
更多相關文章
  • 今天我們來講一下解釋器模式。 什麼叫解釋器模式呢?解釋器模式,給定一個語言,定義她的文法的一種表示,並定義一個解釋器,這個解釋器使用該表示來解釋語言中的句子。如果一種特定類型的問題發生的頻率足夠高,那麼可能就值得將該問題的各個實例表述為一個簡單語言的句子,這樣就可以構建一個解釋器,該解釋器通過/解釋 ...
  • 一、異同 熟悉Spring的應該也都瞭解它的IOC的功能,那麼對於在OSGI開發環境下,在使用IOC功能時有什麼不同呢?最重要的一點就是Spring上下文對象,每個Spring-Powered Bundle都有自身的Spring上下文對象,而傳統的J2EE開發環境只有一個Spring上下文對象,所以 ...
  • 今天我們來講一下享元模式。 我們在工作之餘可能會接一些私活,比如,幫人開發一個網站,幫人開發一個私人博客。隨著私活的增多,會發現,有很多項目是有相同之處的,比如,幫人開發一個網站,你會發現,之前做的一些網站的代碼單元是可以公共的。所以,即便是有很多的私活,我們不要盲目的去做一些項目,我們要善於發現, ...
  • 環境準備: 部署兩台 tomcat 8.0 安裝 redis 伺服器 下載工具庫( commons-pool2-2.3.jar、jedis-2.7.2.jar 、改良版的 tomcat-redis-session-manager.jar ) 環境搭建: 拷貝 commons-pool2-2.3.ja ...
  • action接收請求參數 在web開發中,去接收請求參數來獲得表單信息非常的常見,自己也總結整理了有關Struts2通過action接收請求參數的幾種方法。 Struts2 提供三種數據封裝的方式: (1) Action 本身作為model對象,通過成員setter封裝 (2) 創建獨立model對 ...
  • 1. this指針的用處: 一個對象的this指針並不是對象本身的一部分,不會影響sizeof(對象)的結果。this作用域是在類內部,當在類的非靜態成員函數中訪問類的非靜態成員的時候,編譯器會自動將對象本身的地址作為一個隱含參數傳遞給函數。也就是說,即使你沒有寫上this指針,編譯器在編譯的時候也 ...
  • 本系列所有文章 如何一步一步用DDD設計一個電商網站(一)—— 先理解核心概念 如何一步一步用DDD設計一個電商網站(二)—— 項目架構 如何一步一步用DDD設計一個電商網站(三)—— 初涉核心域 如何一步一步用DDD設計一個電商網站(四)—— 把商品賣給用戶 如何一步一步用DDD設計一個電商網站( ...
  • 今天我們來講一下中介者模式。 什麼叫中介者模式呢?中介者模式,用一個中介對象來封裝一系列的對象交互,中介者使各對象不需要顯示的相互引用,從而使其耦合鬆散,而且可以獨立的改變他們之間的交互。 我們拿兩個不認識的同事通過第三人打招呼這個情景,來看一下中介者模式是什麼樣的: 客戶端調用 中介者模式很容易再 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...