今天我們來講一下職責鏈模式。首先我們來模擬一下下麵這個場景。 一、案例 在公司,我們需要向領導請假,向領導申請加薪,不同級別的領導會做出相應的批示。下麵我們用簡單的控制台應用程式來模擬一下這個案例。 客戶端調用: 好,下麵我們來分析一下上述代碼,看看有什麼問題和缺陷。 ①: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 }
好了,職責鏈模式就講到這裡了,下一篇我們講 中介者模式
本系列將持續更新,喜歡的小伙伴可以點一下關註和推薦,謝謝大家的支持