无废话C#设计模式之十七:Chain Of Resp.
意图
使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象能处理请求为止。
场景
假设我们在制作一个游戏的客服系统,客服有三种角色,分别是普通客服、客服经理和客服总监。玩家在网站中提问后,根据问题的分类和重要性处理的流程不一样。规则如下:
l 分类为1(游戏问题)和2(角色问题)的问题会由普通客服处理。
l 分类为3(充值问题)和4(账户问题)的问题会由客服经理处理。
l 普通客服和客服经理都没有能处理的问题由客服总监进行处理。
l 所有的问题都分为普通问题和重要问题,如果问题是重要问题则需要上一级的客服进行审核(普通客服回复的问题需要客服经理审核、客服经理回答的问题需要客服总监审核)。
这个处理的业务规则比较复杂,您可能会想到创建三个具体客服类型继承抽象客服,然后根据问题的性质传给不同的具体客服来处理。可是这样做有几个缺点:
l 客户端需要知道三个角色能处理的问题属性,三个角色能处理的问题应该只有三个角色自己清楚就可以了。
l 客户端需要和三个角色发生耦合,并且在一个处理过程中会先后调用不同的角色。普通客服在回复了重要问题后应该通知客服经理来审核,现在这个过程交给了客户端去做
客户端知道了太多客服处理问题的细节,对于玩家来说他只需要知道把这些问题告诉客服人员并且得到客服人员的处理结果,具体背后的处理流程是怎么样的它不用知道。由此,引入责任链模式来解决这些问题。
示例代码
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 (CustomerService cs in gmTeam) cs.SetLeader(managerTeam[random.Next(managerTeam.Count)]); } else { foreach (CustomerService cs in gmTeam) cs.SetLeader(directorTeam[random.Next(directorTeam.Count)]); } foreach (CustomerService cs in managerTeam) cs.SetLeader(directorTeam[random.Next(directorTeam.Count)]); // These configs above depends on business logic. }
static void InitGM() { for (int i = 1; i <= 9; i++) { CustomerService gm = new NormalGM("gm" + i); gm.SetResponsibleCaseCategory(new int[] { 1, 2 }); gmTeam.Add(gm); } for (int i = 1; i <= 2; i++) { CustomerService manager = new GMManager("manager" + i); manager.SetResponsibleCaseCategory(new int[] { 3, 4 }); managerTeam.Add(manager); } for (int i = 1; i <=1; i++) directorTeam.Add(new GMDirector("director" + i)); // These configs above should be from database. }
static void Main(string[] args) { InitGM(); InitCOR(); CustomerService 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 { private int caseCategory;
public int CaseCategory { get { return caseCategory; } }
private bool importantCase;
public bool ImportantCase { get { return importantCase; } }
private string reply;
public string Reply { get { return reply ; } set { reply = value; } }
public Case(int caseCategory, bool importantCase) { this.caseCategory = caseCategory; this.importantCase = importantCase; } }
abstract class CustomerService { protected CustomerService leader; protected List<int> responsibleCaseCategory = new List<int>(); protected string name;
public string Name { get { return 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[] responsibleCaseCategory) { foreach (int i in responsibleCaseCategory) this.responsibleCaseCategory.Add(i); } }
class NormalGM : CustomerService { public NormalGM(string name) : |