今天我们来讲一下职责链模式。首先我们来模拟一下下面这个场景。
一、案例
在公司,我们需要向领导请假,向领导申请加薪,不同级别的领导会做出相应的批示。下面我们用简单的控制台应用程序来模拟一下这个案例。
1 /// <summary> 2 /// 申请类 3 /// </summary> 4 class Request 5 { 6 //申请类别 7 private string requestType; 8 public string RequestType 9 { 10 get 11 { 12 return requestType; 13 } 14 15 set 16 { 17 requestType = value; 18 } 19 } 20 //申请内容 21 private string requestContent; 22 public string RequestContent 23 { 24 get 25 { 26 return requestContent; 27 } 28 29 set 30 { 31 requestContent = value; 32 } 33 } 34 //数量 35 private int number; 36 public int Number 37 { 38 get 39 { 40 return number; 41 } 42 43 set 44 { 45 number = value; 46 } 47 } 48 } 49 50 /// <summary> 51 /// 管理者类 52 /// </summary> 53 class Manager 54 { 55 protected string name; 56 57 public Manager(string name) 58 { 59 this.name = name; 60 } 61 //得到结果 62 public void GetResult(string managerLevel, Request request) 63 { 64 //比较长的方法,多条的分支,这些其实都是代码坏味道 65 if (managerLevel == "经理") 66 { 67 if (request.RequestType == "请假" && request.Number <= 2) 68 { 69 Console.WriteLine($"{name}:{request.RequestContent} 数量{request.Number} 被批准"); 70 } 71 else 72 { 73 Console.WriteLine($"{name}:{request.RequestContent} 数量{request.Number} 我无权处理"); 74 } 75 } 76 else if (managerLevel == "总监") 77 { 78 if (request.RequestType == "请假" && request.Number <= 5) 79 { 80 Console.WriteLine($"{name}:{request.RequestContent} 数量{request.Number} 被批准"); 81 } 82 else 83 { 84 Console.WriteLine($"{name}:{request.RequestContent} 数量{request.Number} 我无权处理"); 85 } 86 } 87 else if (managerLevel=="总经理") 88 { 89 if (request.RequestType=="请假") 90 { 91 Console.WriteLine($"{name}:{request.RequestContent} 数量{request.Number} 被批准"); 92 } 93 else if (request.RequestType=="加薪"&&request.Number<=500) 94 { 95 Console.WriteLine($"{name}:{request.RequestContent} 数量{request.Number} 被批准"); 96 } 97 else if (request.RequestType == "加薪" && request.Number > 500) 98 { 99 Console.WriteLine($"{name}:{request.RequestContent} 数量{request.Number} 再说吧"); 100 } 101 } 102 } 103 }
客户端调用:
1 public static void Main() 2 { 3 //三个管理者 4 Manager jinli = new Manager("金立"); 5 Manager zongjian = new Manager("宗剑"); 6 Manager zhongjingli = new Manager("钟精励"); 7 8 //小魔王请求加薪1000 9 Request request = new Request(); 10 request.RequestType = "加薪"; 11 request.RequestContent = "小魔王请求加薪"; 12 request.Number = 1000; 13 14 //不同级别对此请求做判断和处理 15 jinli.GetResult("经理", request); 16 zongjian.GetResult("总监", request); 17 zhongjingli.GetResult("总经理", request); 18 19 //请假3天 20 Request request2 = new Request(); 21 request2.RequestType = "请假"; 22 request2.RequestContent = "小魔王请假"; 23 request2.Number = 3; 24 25 // 不同级别对此请求做判断和处理 26 jinli.GetResult("经理", request2); 27 zongjian.GetResult("总监", request2); 28 zhongjingli.GetResult("总经理", request2); 29 30 Console.ReadKey(); 31 }
好,下面我们来分析一下上述代码,看看有什么问题和缺陷。
①:GetResult这个方法太长,分支太多,让人感觉很不舒服,代码坏了味道。违背了单一职责的原则
②:如果还有其他的管理级别的管理者,那么,就需要修改Manager类,违背了开放-封闭原则。
我们如何才能不仅实现功能,而且还能解决上述的问题呢?下面就是我们要讲的职责链模式了。
什么是职责链模式呢?职责链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
我们来看一下它的代码结构
1 //定义一个处理请示的接口 2 abstract class Handler 3 { 4 protected Handler successor; 5 //设置继任者 6 public void SetSuccessor(Handler successor) 7 { 8 this.successor = successor; 9 } 10 //处理请求的抽象方法 11 public abstract void HandleRequest(int request); 12 } 13 14 //具体处理者类,处理它所负责的请求,可访问它的后继者,如果可处理请求就处理它, 15 //否则,将该请求转发给它的后继者。 16 class ConcreteHandler1 : Handler 17 { 18 public override void HandleRequest(int request) 19 { 20 if (request >= 0 && request < 10) 21 { 22 Console.WriteLine($"{this.GetType().Name}{request}"); 23 } 24 else if (successor != null) 25 { 26 //转移到下一位去处理 27 successor.HandleRequest(request); 28 } 29 } 30 } 31 class ConcreteHandler2 : Handler 32 { 33 public override void HandleRequest(int request) 34 { 35 if (request >= 10) 36 { 37 Console.WriteLine($"{this.GetType().Name}{request}"); 38 } 39 else if (successor != null) 40 { 41 //转移到下一位去处理 42 successor.HandleRequest(request); 43 } 44 } 45 }
客户端
1 public static void Main() 2 { 3 Handler h1 = new ConcreteHandler1(); 4 Handler h2 = new ConcreteHandler2(); 5 h1.SetSuccessor(h2); 6 7 int[] requests = {2, 5, 14, 22}; 8 foreach (int request in requests) 9 { 10 h1.HandleRequest(request); 11 } 12 Console.ReadKey(); 13 }
这当中,最关键的是当客户提交一个请求时,请求是沿着链传递直至有一个ConcreteHandler对象负责处理它。接收者和发送者都没有对方的明确消息,且链中的对象自己也并不知道链的结构。结果是职责链可简化对象的相互连接,他们仅需保持一个指向其后继者的引用,而不需要保持它所有的候选接受着的引用。
下面,我们用职责链模式将我们案例重构一下。
1 /// <summary> 2 /// 申请类 3 /// </summary> 4 class Request 5 { 6 //申请类别 7 private string requestType; 8 public string RequestType 9 { 10 get 11 { 12 return requestType; 13 } 14 15 set 16 { 17 requestType = value; 18 } 19 } 20 //申请内容 21 private string requestContent; 22 public string RequestContent 23 { 24 get 25 { 26 return requestContent; 27 } 28 29 set 30 { 31 requestContent = value; 32 } 33 } 34 //数量 35 private int number; 36 public int Number 37 { 38 get 39 { 40 return number; 41 } 42 43 set 44 { 45 number = value; 46 } 47 } 48 } 49 //管理者 50 abstract class Manager 51 { 52 protected string name; 53 //管理者的上级 54 protected Manager superior; 55 56 public Manager(string name) 57 { 58 this.name = name; 59 } 60 //设置管理者的上级 61 public void SetSuperior(Manager superior) 62 { 63 this.superior = superior; 64 } 65 66 abstract public void RequestApplications(Request request); 67 } 68 //经理 69 class CommonManager:Manager 70 { 71 public CommonManager(string name) : base(name) 72 { 73 } 74 75 public override void RequestApplications(Request request) 76 { 77 if (request.RequestType == "请假" && request.Number <= 2) 78 { 79 Console.WriteLine($"{name}{request.RequestContent}{request.Number}"); 80 } 81 else 82 { 83 //其余的申请都需转到上级 84 if (superior!=null) 85 { 86 superior.RequestApplications(request); 87 } 88 } 89 } 90 } 91 //总监 92 class Majordomo : Manager 93 { 94 public Majordomo(string name) : base(name) 95 { 96 } 97 98 public override void RequestApplications(Request request) 99 { 100 if (request.RequestType == "请假" && request.Number <= 5) 101 { 102 Console.WriteLine($"{name}{request.RequestContent}{request.Number}"); 103 } 104 else 105 { 106 //其余的申请都需转到上级 107 if (superior != null) 108 { 109 superior.RequestApplications(request); 110 } 111 } 112 } 113 } 114 //总经理 115 class GeneralManager : Manager 116 { 117 public GeneralManager(string name) : base(name) 118 { 119 } 120 121 public override void RequestApplications(Request request) 122 { 123 if (request.RequestType == "请假" ) 124 { 125 Console.WriteLine($"{name}{request.RequestContent}{request.Number}"); 126 } 127 else if (request.RequestType=="加薪"&&request.Number<=500) 128 { 129 Console.WriteLine("批准"); 130 } 131 else 132 { 133 Console.WriteLine("再说吧"); 134 } 135 } 136 }
客户端:
1 public static void Main() 2 { 3 CommonManager jinli = new CommonManager("金立"); 4 Majordomo zongjian = new Majordomo("宗剑"); 5 GeneralManager zhongjingli = new GeneralManager("钟精励"); 6 //根据实际需求设置上级 7 jinli.SetSuperior(zongjian); 8 zongjian.SetSuperior(zhongjingli); 9 10 //客户端的申请都是由‘经理’发起,但实际上谁来决策由具体的管理类来处理,客户端不知道。 11 Request request = new Request(); 12 request.RequestType = "请假"; 13 request.RequestContent = "小魔王请假"; 14 request.Number = 1; 15 jinli.RequestApplications(request); 16 17 Request request2 = new Request(); 18 request2.RequestType = "请假"; 19 request2.RequestContent = "小魔王请假"; 20 request2.Number = 4; 21 jinli.RequestApplications(request2); 22 23 Request request3 = new Request(); 24 request2.RequestType = "加薪"; 25 request2.RequestContent = "小魔王加薪"; 26 request2.Number = 1000; 27 jinli.RequestApplications(request2); 28 29 Console.ReadKey(); 30 }
好了,职责链模式就讲到这里了,下一篇我们讲 中介者模式
本系列将持续更新,喜欢的小伙伴可以点一下关注和推荐,谢谢大家的支持