書接上文,狀態模式完美解決了多判斷分支分支問題,符合了我人生信條的第1、第三條。今天來探討一下狀態模式異父異母的親兄弟職責鏈模式,它們都有殊途同歸之妙,實際開發中可根據口味,自行選用。html
今天的故事背景就放在咱們平時 申請加薪、請假等活動中,咱們都知道,隨着咱們申請內容的不一樣,審批人員的等級也不一樣。咱們就先用最簡單的代碼模擬一下git
RequestType枚舉,規範咱們申請的類型app
/// <summary> /// 請求類型 /// </summary> public enum RequestType { /// <summary> /// 請假 /// </summary> Leave, /// <summary> /// 加薪 /// </summary> PayRise }
Requset類,簡單描述申請內容ide
/// <summary> /// 請求 /// </summary> public class Requset { /// <summary> /// 請求類型 /// </summary> public RequestType Type { get; set; } /// <summary> /// 請求數量 /// </summary> public int Number { get; set; } /// <summary> /// 請求說明 /// </summary> public string Content { get { switch (Type) { case RequestType.Leave: return $"請假{Number}天"; case RequestType.PayRise: return $"加薪{Number}元"; default: return "未知"; } } } }
ManagerType枚舉,定義不一樣的審批人員類型優化
/// <summary> /// 管理者類型 /// </summary> public enum ManagerType { PM, CTO, CEO }
Manager類,審批人員,處理咱們的請求code
public class Manager { private readonly ManagerType _managerType; public Manager(ManagerType managerType) { _managerType = managerType; } /// <summary> /// 處理請求 /// </summary> public void Process(Requset requset) { if (_managerType == ManagerType.PM) { if (requset.Type == RequestType.Leave && requset.Number <= 2) { Console.WriteLine($"項目經理 已批准 你的 {requset.Content} 申請"); } else { Console.WriteLine($"項目經理 無權批准 你的 {requset.Content} 申請"); } } else if (_managerType == ManagerType.CTO) { if (requset.Type == RequestType.Leave) { if (requset.Number <= 5) { Console.WriteLine($"CTO 已批准 你的 {requset.Content} 申請"); } else { Console.WriteLine($"CTO 無權批准 你的 {requset.Content} 申請"); } } else { if (requset.Number <= 500) { Console.WriteLine($"CTO 已批准 你的 {requset.Content} 申請"); } else { Console.WriteLine($"CTO 無權批准 你的 {requset.Content} 申請"); } } } else if (_managerType == ManagerType.CEO) { if (requset.Type == RequestType.Leave) { Console.WriteLine($"CEO 已批准 你的 {requset.Content} 申請"); } else { if (requset.Number <= 1000) { Console.WriteLine($"CEO 已批准 你的 {requset.Content} 申請"); } else { Console.WriteLine($"CEO對你的 {requset.Content} 申請 說:「小子,你有點飄啊!」"); } } } } }
客戶端htm
internal class Program { private static void Main(string[] args) { //建立領導 var pm = new Manager(ManagerType.PM); var cto = new Manager(ManagerType.CTO); var ceo = new Manager(ManagerType.CEO); //建立 請假請求 var request1 = new Requset { Type = RequestType.Leave, Number = 5 }; pm.Process(request1); cto.Process(request1); ceo.Process(request1); Console.WriteLine("\n"); //建立 加薪請求 var request2 = new Requset { Type = RequestType.PayRise, Number = 2000 }; pm.Process(request2); cto.Process(request2); ceo.Process(request2); Console.WriteLine("\nHappy Ending~"); Console.ReadLine(); } }
結果展現:對象
項目經理 無權批准 你的 請假5天 申請 CTO 已批准 你的 請假5天 申請 CEO 已批准 你的 請假5天 申請 項目經理 無權批准 你的 加薪2000元 申請 CTO 無權批准 你的 加薪2000元 申請 CEO對你的 加薪2000元 申請 說:「小子,你有點飄啊!」
咱們Code Review後,就會發現Manager.Process()又醜又長呀,一樣是咱們選侍女時出現的三個問題:方法長,分支多,難維護。blog
那咱們怎麼使用職責鏈模式來解決呢?咱們先來了解一下它...繼承
敲黑板·劃重點
定義: 使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。將這個對象連成一個鏈,並沿着這條鏈傳遞請求,知道有一個對象處理請求爲止。
好處: 接收者和發送者都沒有對方的明確信息,且鏈中的對象本身也並不知道鏈的結構。結果是職責鏈可簡化對象的相互鏈接,它們僅需保持一個指向其後繼者的引用,而不須要保持它全部的候選接受者的引用。【下降耦合度】
注意: 一個請求極有可能到了鏈的末端都得不處處理,或者由於沒有正確配置而得不處處理,須要考慮全面!
在下面代碼優化中來深化對定義、好處的理解吧
Manager抽象類,不一樣權限審批人員的基類,能夠設置下一級審批人員,造成一條職責鏈
public abstract class Manager { protected readonly ManagerType _managerType; /// <summary> /// 下一個處理者 /// </summary> protected Manager Successor { get; private set; } public Manager(ManagerType managerType) { _managerType = managerType; } /// <summary> /// 設置下一個處理者 /// </summary> /// <param name="manager"></param> public void SetSuccessor(Manager manager) { Successor = manager; } /// <summary> /// 處理請求 /// </summary> /// <param name="requset"></param> public abstract void Process(Requset requset); }
PM、CTO、CEO類,具體的審批人,實現處理方法Process()
public class PM : Manager { public PM(ManagerType managerType) : base(managerType) { } public override void Process(Requset requset) { if (requset.Type == RequestType.Leave && requset.Number <= 2) { Console.WriteLine($"項目經理 已批准 你的 {requset.Content} 申請"); return; } if (Successor != null) { //交由下一級處理 Successor.Process(requset); } } } public class CTO : Manager { public CTO(ManagerType managerType) : base(managerType) { } public override void Process(Requset requset) { if (requset.Type == RequestType.Leave && requset.Number <= 5) { Console.WriteLine($"CTO 已批准 你的 {requset.Content} 申請"); return; } if (requset.Type == RequestType.PayRise && requset.Number <= 500) { Console.WriteLine($"CTO 已批准 你的 {requset.Content} 申請"); return; } if (Successor != null) { //交由下一級處理 Successor.Process(requset); } } } public class CEO : Manager { public CEO(ManagerType managerType) : base(managerType) { } public override void Process(Requset requset) { if (requset.Type == RequestType.Leave && requset.Number <= 15) { Console.WriteLine($"CEO 已批准 你的 {requset.Content} 申請"); return; } if (requset.Type == RequestType.PayRise && requset.Number <= 1000) { Console.WriteLine($"CEO 已批准 你的 {requset.Content} 申請"); return; } Console.WriteLine($"CEO對你的 {requset.Content} 申請 說:「小子,你有點飄啊!」"); } }
客戶端代碼
internal class Program { private static void Main(string[] args) { //建立領導 var pm = new PM(ManagerType.PM); var cto = new CTO(ManagerType.CTO); var ceo = new CEO(ManagerType.CEO); //設置下一級處理者 pm.SetSuccessor(cto); cto.SetSuccessor(ceo); //建立 請假請求 var request1 = new Requset { Type = RequestType.Leave, Number = 5 }; pm.Process(request1); Console.WriteLine("\n"); //建立 加薪請求 var request2 = new Requset { Type = RequestType.PayRise, Number = 2000 }; pm.Process(request2); Console.WriteLine("\nHappy Ending~"); Console.ReadLine(); } }
結果展現:
CTO 已批准 你的 請假5天 申請 CEO對你的 加薪2000元 申請 說:「小子,你有點飄啊!」
這樣咱們也消除上面三個問題。當需求須要人事加入審批流程時,只須要增長一個繼承Manager的人事類;當需求要求不須要CTO審批,直接由PM轉到CEO時,咱們只用修改PM的SetSuccessor(),這也體現了職責鏈的靈活性。
示例代碼地址: https://gitee.com/sayook/DesignMode/tree/master/ChainOfResponsibility