設計模式之責任鏈


責任鏈模式介紹

通過鏈條連接

責任鏈模式是一種行為設計模式,允許你將請求沿着處理者鏈進行發送。收到請求后,每個處理者均可對請求進行處理,或將其傳遞給鏈上的下個處理者。

責任鏈模式的核心是解決一組服務中的先后執行處理關系。

責任鏈模式可以讓各個服務模塊更加清晰,而每一個模塊可以通過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();
        }
    }

輸出結果

可以通過上面圖片標紅的地方了解到具體輸出的值,第一次(初始位置)時在最后狗類處不繼續執行,第二次(中間位置)在猴子類處不執行,第三次所有的都不執行(第三次到鏈尾了)。

小寄語

人生短暫,我不想去追求自己看不見的,我只想抓住我能看的見的。

我是阿輝,感謝您的閱讀,如果對你有幫助,麻煩點贊、轉發 謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM