设计模式之责任链
責任鏈模式介紹
通過鏈條連接責任鏈模式是一種行為設計模式,允許你將請求沿著處理者鏈進行發送。收到請求后,每個處理者均可對請求進行處理,或將其傳遞給鏈上的下個處理者。
責任鏈模式的核心是解決一組服務中的先后執行處理關系。
責任鏈模式可以讓各個服務模塊更加清晰,而每一個模塊可以通過next的方式進行獲取。而每一個next是由繼承的統一抽象類實現的,最終所有類的職責可以動態的進行編排使用,編排的過程可以做成可配置化。
在使用責任鏈時,如果場景比較固定,可寫死到代碼中進行初始化。但如果業務場景經常變化可以做成xml配置的方式進行處理,也可以保存到數據庫中進行初始化操作。
實際的業務中在使用責任鏈時會進行一系列的包裝,通過把不同的責任節點進行組裝,構成一條完整業務的責任鏈。
責任鏈模式很好的處理單一職責和開閉原則,簡單耦合也使對象關系更加清晰,而且外部的調用方并不需要關系責任鏈是如何處理的。
責任鏈模式結構
處理者
聲明了所有具體處理者的通用接口,該接口通常僅包含單個方法用于請求處理,但有時其還會包含一個設置鏈上下處理者的方法。基礎處理者 是一個可選的類,你可以將所有處理者共用的樣本代碼放置在其中。(通常情況下,該類定義了一個保存對于下個處理者引用的成員變量??蛻舳丝赏ㄟ^將處理者的構造函數或設定方法來創建鏈。該類還可以實現默認的處理行為,確定下個處理者存在后再將請求傳遞給它。)
具體處理者 包含處理請求的實際代碼。每個處理者接收到請求后,都必須決定是否進行處理,或者說是否沿著鏈傳遞請求。
客戶端
可根據程序邏輯一次性或者動態的生成鏈。
適用場景
當程序需要使用不同方式處理不同種類請求,而且請求類型和順序預先未知時。
業務邏輯必須按順序執行多個處理者時。
處理者及其順序必須在運行時進行改變,可以使用責任鏈模式。
實現方式
聲明處理者接口并描述請求處理方法的簽名
可以根據處理者接口創建抽象處理者基類(需要一個成員變量來存儲指向鏈上下個處理者的引用)
創建具體的處理者子類并實現其處理方法。(每個處理者在接收到請求后都必須做兩個決定:1、是否自行處理請求;2、是否將該請求沿著鏈進行傳遞。)
客戶端可自行組裝鏈,或者從其他對象處獲得預先組裝好的鏈。
客戶端可觸發鏈中的任意處理者,而不僅僅是第一個。請求將通過鏈進行傳遞,直至某個處理者拒絕繼續傳遞或者請求到達鏈尾。
Demo
責任鏈模式在C#程序中并不常見,因為它僅在代碼與對象鏈打交道時才能發揮作用。
處理者接口
????///?<summary>///?處理者接口///?</summary>public?interface?IHandler?{IHandler?SetNext(IHandler?handler);object?Handle(object?request);}抽象類
????///?<summary>///?抽象類///?</summary>public?abstract?class?AbstractHandler?:IHandler{private?IHandler?_nextHandler;public?IHandler?SetNext(IHandler?handler){this._nextHandler?=?handler;return?handler;}///?<summary>///?虛方法,在子類繼承中需實現此方法。///?</summary>///?<param?name="request"></param>///?<returns></returns>public?virtual??object?Handle(object?request){if?(this._nextHandler?!=null){return?this._nextHandler.Handle(request);}else{return?null;}}}實現抽象類
????///?<summary>///?猴子類///?</summary>public?class?MonkeyHandler?:?AbstractHandler{public?override?object?Handle(object?request){if?((request?as?string)=="猴子"){return?"在猴子類中"+request.ToString();}else{return?base.Handle(request);????????????????????????//父類中的Handle方法????????}}}///?<summary>///?松鼠類///?</summary>public?class?SquirreHandler?:?AbstractHandler{public?override?object?Handle(object?request){if?((request?as?string)?==?"松鼠"){return?"在松鼠類中"?+?request.ToString();}else{return?base.Handle(request);????????????????????????//父類中的Handle方法????????}}}///?<summary>///?小狗類///?</summary>public?class?DogHandler?:?AbstractHandler{public?override?object?Handle(object?request){if?((request?as?string)?==?"小狗"){return?"在小狗類中"?+?request.ToString();}else{return?base.Handle(request);????????????????????????//父類中的Handle方法????????}}}????客戶端和Main()驗證
????class?Client?{public?static?void?ClientCode(AbstractHandler?handler)?{foreach?(var?item?in?new?List<string>{"松鼠","猴子","人"}){Console.WriteLine("到底是誰:"+item);var?result?=?handler.Handle(item);if?(result!=null){Console.WriteLine("誰:"+result);}else{Console.WriteLine("No?Find");}}Console.WriteLine("開始");}}class?Program{static?void?Main(string[]?args){var?monkey?=?new?MonkeyHandler();var?squirrel?=?new?SquirreHandler();var?dog?=?new?DogHandler();monkey.SetNext(squirrel).SetNext(dog);??????//構建鏈條Console.WriteLine("----------第一次");Client.ClientCode(monkey);Console.WriteLine();Console.WriteLine("第二次");Client.ClientCode(squirrel);Console.WriteLine("第三次");Client.ClientCode(dog);Console.ReadKey();}} 輸出結果可以通過上面圖片標紅的地方了解到具體輸出的值,第一次(初始位置)時在最后狗類處不繼續執行,第二次(中間位置)在猴子類處不執行,第三次所有的都不執行(第三次到鏈尾了)。
小寄語
人生短暫,我不想去追求自己看不見的,我只想抓住我能看的見的。
我是阿輝,感謝您的閱讀,如果對你有幫助,麻煩點贊、轉發 ?謝謝。
總結
- 上一篇: .NET Core 中有等价的 Http
- 下一篇: Dapr 客户端 搭配 WebApiCl