首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 設計模式無廢話系列(十七):Chain of Responsibility 責任鏈模式

     編輯:關於C#

意圖

讓多個對象都有機會處理請求,避免發送者與接收者耦合。將對象連成鏈,沿鏈傳遞請求,直到有對象處理為止。

適用場景

遊戲客服系統:普通客服、客服經理、客服總監三角色。處理規則:

  • 分類 1、2(遊戲/角色問題)→ 普通客服
  • 分類 3、4(充值/帳號問題)→ 客服經理
  • 無人能處理 → 客服總監
  • 重要問題需上級審核(普通客服回覆→經理審;經理回覆→總監審)

若客戶端直接依賴三角色並協調流程,會知曉過多細節。引入責任鏈,客戶端僅需拋給入口點。

完整範例程式碼

using System;
using System.Collections.Generic;
using System.Text;

namespace ChainOfRespExample
{
    class Program
    {
        static List<CustomerService> gmTeam = new List<CustomerService>();
        static List<CustomerService> managerTeam = new List<CustomerService>();
        static List<CustomerService> directorTeam = new List<CustomerService>();
        static Random random = new Random();

        static void InitCOR()
        {
            if (managerTeam.Count > 0)
                foreach (var cs in gmTeam) cs.SetLeader(managerTeam[random.Next(managerTeam.Count)]);
            else
                foreach (var cs in gmTeam) cs.SetLeader(directorTeam[random.Next(directorTeam.Count)]);

            foreach (var cs in managerTeam) cs.SetLeader(directorTeam[random.Next(directorTeam.Count)]);
        }

        static void InitGM()
        {
            for (int i = 1; i <= 9; i++)
            {
                var gm = new NormalGM("gm" + i);
                gm.SetResponsibleCaseCategory(new int[] { 1, 2 });
                gmTeam.Add(gm);
            }
            for (int i = 1; i <= 2; i++)
            {
                var m = new GMManager("manager" + i);
                m.SetResponsibleCaseCategory(new int[] { 3, 4 });
                managerTeam.Add(m);
            }
            for (int i = 1; i <= 1; i++) directorTeam.Add(new GMDirector("director" + i));
        }

        static void Main(string[] args)
        {
            InitGM();
            InitCOR();
            var gm = gmTeam[random.Next(gmTeam.Count)];
            gm.HandleCase(new Case(1, false));
            Console.WriteLine(Environment.NewLine);
            gm = gmTeam[random.Next(gmTeam.Count)];
            gm.HandleCase(new Case(2, true));
            Console.WriteLine(Environment.NewLine);
            gm = gmTeam[random.Next(gmTeam.Count)];
            gm.HandleCase(new Case(3, false));
            Console.WriteLine(Environment.NewLine);
            gm = gmTeam[random.Next(gmTeam.Count)];
            gm.HandleCase(new Case(4, true));
            Console.WriteLine(Environment.NewLine);
            gm = gmTeam[random.Next(gmTeam.Count)];
            gm.HandleCase(new Case(5, true));
        }
    }

    class Case
    {
        public int CaseCategory { get; }
        public bool ImportantCase { get; }
        public string Reply { get; set; }
        public Case(int cat, bool imp) { CaseCategory = cat; ImportantCase = imp; }
    }

    abstract class CustomerService
    {
        protected CustomerService leader;
        protected List<int> responsibleCaseCategory = new List<int>();
        protected string name;
        public string Name => name;
        public CustomerService(string name) { this.name = name; }
        public void SetLeader(CustomerService leader) => this.leader = leader;
        public abstract void HandleCase(Case gameCase);
        public void SetResponsibleCaseCategory(int[] cats) => cats.ToList().ForEach(c => responsibleCaseCategory.Add(c));
    }

    class NormalGM : CustomerService
    {
        public NormalGM(string name) : base(name) { }
        public override void HandleCase(Case gameCase)
        {
            if (responsibleCaseCategory.Contains(gameCase.CaseCategory))
            {
                gameCase.Reply = "OK";
                Console.WriteLine($"The case has been replied by {name}");
                if (gameCase.ImportantCase)
                {
                    Console.WriteLine("The reply should be checked.");
                    leader.HandleCase(gameCase);
                }
                else Console.WriteLine("The reply has been sent to player.");
            }
            else if (leader != null)
            {
                Console.WriteLine($"{name} reports this case to {leader.Name}.");
                leader.HandleCase(gameCase);
            }
        }
    }

    class GMManager : CustomerService
    {
        public GMManager(string name) : base(name) { }
        public override void HandleCase(Case gameCase)
        {
            if (responsibleCaseCategory.Contains(gameCase.CaseCategory))
            {
                gameCase.Reply = "OK";
                Console.WriteLine($"The case has been replied by {name}");
                if (gameCase.ImportantCase)
                {
                    Console.WriteLine("The reply should be checked.");
                    leader.HandleCase(gameCase);
                }
                else Console.WriteLine("The reply has been sent to player.");
            }
            else if (gameCase.Reply != null)
            {
                Console.WriteLine($"The case has been checked by {name}");
                Console.WriteLine("The reply has been sent to player.");
            }
            else if (leader != null)
            {
                Console.WriteLine($"{name} reports this case to {leader.Name}.");
                leader.HandleCase(gameCase);
            }
        }
    }

    class GMDirector : CustomerService
    {
        public GMDirector(string name) : base(name) { }
        public override void HandleCase(Case gameCase)
        {
            if (gameCase.Reply != null)
            {
                Console.WriteLine($"The case has been checked by {name}");
                Console.WriteLine("The reply has been sent to player.");
            }
            else
            {
                gameCase.Reply = "OK";
                Console.WriteLine($"The case has been replied by {name}");
                Console.WriteLine("The reply has been sent to player.");
            }
        }
    }
}

程式碼執行結果

有客服經理時的執行結果 無客服經理時的執行結果

程式碼解析

  • Case:請求對象,含分類、重要性、回覆。
  • CustomerService:抽象處理者,持有 leader 參考與責任分類清單,定義統一 HandleCase。
  • NormalGM:具體處理者。屬責任分類 → 回覆 → 重要則上呈審核;不屬 → 轉交上級。
  • GMManager:具體處理者。屬責任分類 → 回覆 → 重要則上呈;不屬但有回覆 → 審核;不屬無回覆 → 轉交上級。
  • GMDirector:頂層處理者。有回覆 → 審核;無回覆 → 直接回覆。鏈終點。
  • 客戶端:InitGM 建立團隊(9 GM、2 經理、1 總監);InitCOR 動態建鏈(無經理時 GM 直連總監);隨機指派 GM 為入口處理 5 種案例。
  • 有經理時:分類 1→GM 結案;2→GM 回覆+經理審;3→GM 轉經理處理;4→GM 轉經理處理+總監審;5→GM→經理→總監。無經理時:所有非 GM 責任分類直接上呈總監。

何時採用

  • 代碼角度:邏輯由不同責任對象完成,客戶端想自訂流程且不想直接耦合多對象。
  • 應用角度:處理流程經過多責任點、流程複雜或僅對外公開單一入口。架構層亦適用(如 .NET 分層異常處理)。

實作要點

  • 抽象責任角色,避免具體責任類耦合。
  • 抽象角色定義後繼者參考,提供配置方法。
  • 具體角色依請求狀態與自身職責判斷:能處理則處理(純責任鏈)或部分處理後上傳(不純責任鏈)。
  • 客戶端負責鏈接,配置不當可能導致請求無人處理。

注意事項

  • 責任鏈 vs State:前者重責任傳遞、客戶端配置鏈;後者重狀態轉換、對客戶端透明。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved