職責鏈模式(Chain of Responsibility): 在現實生活中,常常會出現這樣的事例:一個請求需要多個對象處理,但每個對象的處理條件或許可權不同。如公司員工報銷差旅費,可審批的領導有部分負責人、副總經理、總經理等,但每個領導能審批的金額是不同的,不同的金額需要找相應的領導審批,也就是說要 ...
職責鏈模式(Chain of Responsibility):
在現實生活中,常常會出現這樣的事例:一個請求需要多個對象處理,但每個對象的處理條件或許可權不同。如公司員工報銷差旅費,可審批的領導有部分負責人、副總經理、總經理等,但每個領導能審批的金額是不同的,不同的金額需要找相應的領導審批,也就是說要報銷必須先搞清楚需要誰來審批。職責鏈模式就是為瞭解決這樣的問題產生的。
職責鏈模式,又叫責任鏈模式。是為了避免請求發送者與多個請求處理者耦合在一起,將所有請求的處理者通過前一個對象記住其下一個對象的引用而連成一條鏈。當發生請求時,可將請求沿著這條鏈傳遞,直到有對象處理它為止。
職責鏈模式的角色:
1)抽象處理者(Handler):聲明瞭所有具體處理者的通用介面。 該介面通常僅包含單個方法用於請求處理, 但有時其還會包含一個設置鏈上下個處理者的方法
2)具體處理者(ConcreteHandler):包含處理請求的實際代碼。 每個處理者接收到請求後, 都必須決定是否進行處理, 以及是否沿著鏈傳遞請求。處理者通常是獨立且不可變的, 需要通過構造函數一次性地獲得所有必要地數據。
3)請求信息(Request):定義請求的信息。
4)客戶端(Client):可根據程式邏輯一次性或者動態地生成鏈。值得註意的是,請求可發送給鏈上的任意一個處理者,而非必須是第一個處理者。
責任鏈的實現:(以請假為例)
1 internal class Program 2 { 3 private static void Main(string[] args) 4 { 5 //構建各個領導人 6 Leader director = new Director("張三");//主任 7 Leader manager = new Manager("李四");//經理 8 Leader generalManager = new GeneralManager("王五");//總經理 9 //設置各個責任鏈上的關係 10 director.setNextLeader(manager);//主任的下一個審批人為經理 11 manager.setNextLeader(generalManager);//經理的下一個審批人為總經理 12 13 //開始請假 14 LeaveRequest request = new LeaveRequest("小明", 5, "旅游"); 15 director.HandleRequest(request);//小明提交了請假申請給主任 16 } 17 } 18 19 /// <summary> 20 /// 請假的信息 21 /// </summary> 22 public class LeaveRequest 23 { 24 public string EmplName { get; set; } 25 public int LeaveDays { get; set; } 26 public string Reason { get; set; } 27 28 public LeaveRequest(string emplName, int leaveDays, string reason) 29 { 30 this.EmplName = emplName; 31 this.LeaveDays = leaveDays; 32 this.Reason = reason; 33 } 34 } 35 36 /// <summary> 37 /// 管理責任鏈上的對象處理的抽象類 38 /// </summary> 39 public abstract class Leader 40 { 41 protected string name; 42 protected Leader nextLeader;//下一個繼承者 43 44 public Leader(string name) 45 { 46 this.name = name; 47 } 48 49 /// <summary> 50 /// 設置責任鏈上的下一個繼承者 51 /// </summary> 52 /// <param name="leader"></param> 53 public void setNextLeader(Leader leader) 54 { 55 this.nextLeader = leader; 56 } 57 58 /// <summary> 59 /// 處理請求的抽象方法 60 /// </summary> 61 /// <param name="leader"></param> 62 public abstract void HandleRequest(LeaveRequest leader); 63 } 64 65 /// <summary> 66 /// 主任: 處理小於等於3天的假期 67 /// </summary> 68 public class Director : Leader 69 { 70 public Director(string name) 71 : base(name) 72 { 73 } 74 75 /// <summary> 76 /// 責任鏈上對象對請求的具體處理 77 /// </summary> 78 /// <param name="leader"></param> 79 public override void HandleRequest(LeaveRequest leader) 80 { 81 if (leader.LeaveDays <= 3) 82 { 83 Console.WriteLine($"請假人:{leader.EmplName},天數{leader.LeaveDays},理由:{leader.Reason}"); 84 Console.WriteLine($"審批人:{this.name } 主任,審批通過!"); 85 } 86 else 87 { 88 if (this.nextLeader != null) 89 { 90 this.nextLeader.HandleRequest(leader); 91 } 92 } 93 } 94 } 95 96 /// <summary> 97 /// 經理: 處理大於3天,小於等於10天的假期 98 /// </summary> 99 public class Manager : Leader 100 { 101 public Manager(string name) 102 : base(name) 103 { 104 } 105 106 /// <summary> 107 /// 責任鏈上對象對請求的具體處理 108 /// </summary> 109 /// <param name="leader"></param> 110 public override void HandleRequest(LeaveRequest leader) 111 { 112 if (leader.LeaveDays > 3 && leader.LeaveDays <= 10) 113 { 114 Console.WriteLine($"請假人:{leader.EmplName},天數{leader.LeaveDays},理由:{leader.Reason}"); 115 Console.WriteLine($"審批人:{this.name } 經理,審批通過!"); 116 } 117 else 118 { 119 if (this.nextLeader != null) 120 { 121 this.nextLeader.HandleRequest(leader); 122 } 123 } 124 } 125 } 126 127 /// <summary> 128 /// 總經理: 處理大於10天,小於等於30天的請假信息 129 /// </summary> 130 public class GeneralManager : Leader 131 { 132 public GeneralManager(string name) 133 : base(name) 134 { 135 } 136 137 /// <summary> 138 /// 責任鏈上對象對請求的具體處理 139 /// </summary> 140 /// <param name="leader"></param> 141 public override void HandleRequest(LeaveRequest leader) 142 { 143 if (leader.LeaveDays > 10 && leader.LeaveDays <= 30) 144 { 145 Console.WriteLine($"請假人:{leader.EmplName},天數{leader.LeaveDays},理由:{leader.Reason}"); 146 Console.WriteLine($"審批人:{this.name } 總經理,審批通過!"); 147 } 148 else 149 { 150 if (this.nextLeader != null) 151 { 152 this.nextLeader.HandleRequest(leader); 153 } 154 else 155 { 156 Console.WriteLine($"你瘋了!!!"); 157 } 158 } 159 } 160 }
從實現上可以看出,每個領導只處理自己能力範圍內的事情,不是自己的堅決不處理;同時職責鏈是動態構建的,下一個處理者由調用者自己設置;缺少處理對象可以直接添加,符合開閉原則。
職責鏈的優缺點:
優點:
1)請求者和接收者松耦合。在職責鏈模式中,請求者並不知道接收者是誰,也不知道具體如何處理,請求者只是負責向職責鏈發送請求就可以了。而每個職責對象也不用管請求者或者是其他的職責對象,只負責處理自己的部分,其他的就交給其他的職責對象去處理。也就是說,請求者和接受者是完全解耦的。
2)動態組合職責。職責鏈模式會把功能處理分散到單獨的職責對象中,然後再使用的時候,可以動態組合職責形成職責鏈,從而可以靈活地給對象分配職責,也可以靈活地實現和改變對象的職責。
3)減少代碼中的if..else..判斷,優化代碼。
缺點:
1)產生很多細粒度對象。職責鏈模式會把功能處理分散到單獨的職責對象中,也就是每個職責對象只處理一個方面的功能,要把整個業務處理完,需要很多職責對象的組合,這樣會產生大量的細粒度職責對象。
2)不一定能被處理。職責鏈模式的每個職責對象只負責自己處理的那一部分,因此可能會出現某個請求把整個鏈傳遞完了都沒有職責對象處理它。這就需要使用職責鏈模式的時候,需要提供預設的處理,並且註意構造的鏈的有效性。
3)職責鏈建立的合理性要靠客戶端來保證,增加了客戶端的複雜性,可能由於職責鏈的錯誤設置而導致系統出錯,如可能會造成迴圈調用。
職責鏈的應用場景:
1)有多個對象可以處理一個請求,哪個對象處理該請求由運行時刻自動確定。
2)可動態指定一組對象處理請求,或添加新的處理者。
3)在不明確指定請求處理者的情況下,向多個處理者中的一個提交請求。
參考:https://www.cnblogs.com/cxxjohnson/p/6403849.html