基本介紹:
“責任鏈”顧名思義,是指一個需要負責處理請求的鏈條。
每個鏈條節點都是一個單獨的責任者,由責任者自己決定是否處理請求或交給下一個節點。
在設計模式中的解釋則為:為請求建立了一個接收者物件的鏈。適用於有多個物件可以處理同一個請求,但具體由哪個物件處理則在執行時動態決定的情況。
俗話說起來就是一群領導組成了一個上下級鏈路關係,每個領導的職責各不相同,老百姓辦事情的時候肯定沒辦法知道該找哪個領導。
這個時候就可以把需要辦的事情交給接待人員,由接待人員自行判斷是不是可以處理或者交給上級處理,至於是誰給我負責,那我這個小老百姓並不關心,只要辦了就可以了。
老百姓辦的事情就是請求,接待人員和領導群組成的集合就是責任鏈,每個領導負責自己的職責,至於最後是誰負責,那就根據具體事情一級一級的傳遞動態決定。
這麼做的好處也顯而易見,我的請求可以是任意的,具體要不要解決由誰解決,都交給責任鏈自己去判斷。
舉例說明:
公司的請假系統,當一個員工提交請假申請時,根據請假天數和職位的不同,需要由不同等級的領導審批。
專案組長》部門經理》總經理》董事長》董事會就組成了一個責任鏈。
普通員工和專案組長都是請假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 }
總結:
責任鏈模式屬於行為型模式。它使多個物件都有機會處理請求,從而避免傳送者和接受者之間的耦合關係。將這個物件連成一條鏈,並沿著這條鏈傳遞該請求,直到有一個物件處理它為止。