行为型模式之责任链模式
責任鏈模式(Chain of Responsibility Pattern)為請求創建了一個接收者對象的鏈.這種模式給與請求的類型,對請求的發送者和接收者進行解耦.這種類型的設計模式屬于行為型模式 在這種模式中,通常每個接收者都包含對另一個接收者的引用。如果一個對象不能處理該請求,那么它會把相同的請求傳給下一個接收者,依此類推。
簡單用圖表示一下:
場景
公司中的某個員工小A最近表現很好,工作努力、解決問題效率高,所以小A想提出漲工資的要求。但是公司的管理序列負責,該怎么辦? 首先,小A找到了直屬部門經理,但是部門經理說我沒有權限。 接下來,小A去找部門總監,同樣部門總監也說沒有權限; 最后,小A輾轉找到了總經理,總經理經過認真考察,同意了A的請求。
仔細分析上面的場景,當A提出漲薪的申請時,后續處理這個申請的對象,部門經理,部門總監,總經理,自然的形成了一個鏈,從部門經理-部門總監-總經理,客戶端的申請請求就在這個鏈中傳遞,直到有領導處理為止。看起來,上面的功能要求很適合采用職責鏈來處理這個業務。
要想處理請求的流程可以靈活的變動,一個基本思路,那就是動態構建流程步驟,這樣隨時都可以重新組合新的流程來.而要讓處理請求的對象也要很靈活,那就要讓它足夠簡單,最好是只實現單一的功能,或者是有限的功能,這樣更有利于修改和復用。
為什么動態構建還要單一呢?比如現在A提出的申請,直接先找部門總監,完了再看總經理,沒有部門經理什么事,他壓根不參與,之前的邏輯你就要重新修改.或者審批不但只是通過不通過,還要加上每個處理對象對漲薪的多少有決定,那處理的邏輯也變了.所以上面要求構建流程要動態并且單一
責任鏈模式就很好的體現了上述的基本思路,那么它是怎么做的呢
- 首先責任鏈模式會定義一個所以處理請求的對象都要繼承實現的抽象類,這樣就有利于隨時切換新的實現;
- 其次每個處理請求對象只實現業務流程中的一步業務處理,這樣使其變得簡單
- 最后責任鏈模式會動態的來組合這些處理請求的對象,把他們按照流程動態組合起來,并要求它們依次調用,這樣就動態的實現了流程
這樣一來,如果流程發生了變化,只要重新組合就好了;如果某個處理的業務功能發生了變化,一個方案是修改該處理對應的處理對象,另一個方案是直接提供一個新的實現,然后在組合流程的時候,用新的實現替換掉舊的實現就可以了。
在iOS中,最典型的例子就是UIView對事件處理的響應函數
模式結構和說明
Handler:定義職責的接口,通常在這里定義處理請求的方法,可以在這里實現后繼鏈。 ConcreteHandler:實現職責的類,在這個類里面,實現對在它職責范圍內請求的處理,如果不處理,就繼續轉發請求給后繼者。 Client:職責鏈的客戶端,向鏈上的具體處理者對象提交請求,讓職責鏈負責處理。
示例代碼
用責任鏈模式來重寫場景示例,功能:當某人提出漲薪后,該請求會在部門經理-部門總監-總經理這樣一條領導處理鏈上進行傳遞,發出請求的人并不知道誰來處理他的請求,每個領導會根據自己的職責范圍,來判斷是處理請求還是把請求交給更高級的領導,只要有領導處理了,傳遞就結束了
需要把每位領導的處理獨立出來,實現成單獨的職責處理對象,然后為它們提供一個公共的、抽象的父職責對象,這樣就可以在客戶端來動態的組合職責鏈,實現不同的功能要求了
模式講解
1. 認識責任鏈模式
模式功能
職責鏈模式主要用來處理:“客戶端發出一個請求,有多個對象都有機會來處理這一個請求,但是客戶端不知道究竟誰會來處理他的請求”,這樣的情況。也就是需要讓請求者和接收者解耦,這樣就可以動態的切換和組合接收者了
在標準的職責鏈模式里面,是只要沒有有對象處理了請求,這個請求就到此為止,不再被傳遞和處理了。
隱式接受者
當客戶端發出請求的時候,客戶端并不知道誰會真正處理他的請求,客戶端只知道他提交請求的第一個對象。從第一個處理對象開始,整個職責鏈里面的對象,要么自己處理請求,要么繼續轉發給下一個接收者。 也就是對于請求者而言,并不知道最終的接收者是誰,但是一般情況下,總是會有一個對象來處理的,因此稱為隱式接收者。
誰來處理
職責鏈中那么多處理對象,到底誰來處理請求呢,這個是在運行時期動態決定的。當請求被傳遞到某個處理對象的時候,這個對象會按照已經設定好的條件來判斷,是否屬于自己處理的范圍,如果是就處理,如果不是就轉發請求給下一個對象。
當然,在職責鏈模式中,請求不一定會被處理,因為可能沒有合適的處理者,請求在職責鏈里面從頭傳遞到尾,每個處理對象都判斷不屬于自己處理,最后請求就沒有對象來處理。
2. 處理多種請求
前面的示例都是同事職責鏈處理一種請求的情況,現在有這樣得需求,A除了想漲薪資外,還想換個崗位,假設還是同一流程,也就是說還是同一責任鏈,雖然流程相同,但是每個處理類需要處理兩種請求,它們的具體業務邏輯是不一樣的,那么該如何實現呢?
有兩種方式:
- 為每種業務單獨定義一個方法,然后客戶端根據不同的需要調用不同的方法
實現上很容易,但有一個很明顯的問題,那就是只要增加一個業務,就需要修改職責接口,這是很不靈活的,在編程中強調面向接口編程,因此接口應該相對保持穩定,接口一改,需要修改的地方就太多了,頻繁修改接口絕對不是個好主意。
那有沒有什么好方法來實現呢?分析一下現在變化的東西:
一是不同的業務需要傳遞的業務數據不同; 二是不同的業務請求的方法不同; 三是不同的職責對象處理這些不同的業務請求的業務邏輯不同;
那么怎么解決呢,就是下面的第二種方法
- 首先定義一套通用的調用框架,用一個通用的請求對象來封裝請求傳遞的參數;然后定義一個通用的調用方法,這個方法不去區分具體業務,所有的業務都是這一個方法,那么具體的業務如何區分呢,就是在通用的請求對象里面會有一個業務的標記;到了職責對象里面,愿意處理就跟原來一樣的處理方式,如果不愿意處理,就傳遞到下一個處理對象就好了。
3. 優缺點
優點
- 職責鏈模式使得一個對象無須知道是其他哪一個對象處理其請求,對象僅需知道該請求會被處理即可,接收者和發送者都沒有對方的明確信息,且鏈中的對象不需要知道鏈的結構,由客戶端負責鏈的創建,降低了系統的耦合度。
- 請求處理對象僅需維持一個指向其后繼者的引用,而不需要維持它對所有的候選處理者的引用,可簡化對象的相互連接。
- 在給對象分派職責時,職責鏈可以給我們更多的靈活性,可以通過在運行時對該鏈進行動態的增加或修改來增加或改變處理一個請求的職責。
- 在系統中增加一個新的具體請求處理者時無須修改原有系統的代碼,只需要在客戶端重新建鏈即可,從這一點來看是符合“開閉原則”的。
缺點
- 因為一個請求沒有明確的接收者,該請求可能一直到鏈的末端都得不到處理;一個請求也可能因職責鏈沒有被正確配置而得不到處理。
- 對于比較長的職責鏈,請求的處理可能涉及到多個處理對象,系統性能將受到一定影響,而且在進行代碼調試時不太方便。
- 如果建鏈不當,可能會造成循環調用,將導致系統陷入死循環。
Demo地址
轉載于:https://juejin.im/post/5d5fa8b4f265da03b638b589
總結
以上是生活随笔為你收集整理的行为型模式之责任链模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .Net 零星小知识
- 下一篇: Vue的示例