原文:C#设计模式之二十职责链模式(Chain of Responsibility Pattern)【行为型】
一、引言
今天我们开始讲“行为型”设计模式的第八个模式,该模式是【职责链模式】,英文名称是:Chain of Responsibility Pattern。让我们看看现实生活中的例子吧,理解起来可能更容易。我们看看某公司的采购流程吧。某公司的规章制度规定,采购原质料的总价在5万之内,只需要经理级另外人批准即可,采购总价大于5万小于10万的则需要财务经理进行批准,总价大于10万小于30万的需要总经理批准,而总价大于30万的则需要通过董事会会议讨论决定。对付这样一个需求,最直接的要领就是设计一个要领,,该要领接受的参数是采购的总价,然后在这个要领内对价格进行判断,然后针对差此外条件交给差别级另外角色去措置惩罚惩罚,如果情况就是这样,不乱了,这样做很好,没问题。如果我们又有新的条件要增加该怎么办呢?我们不得不去改削本来设计的要领来再添加一个条件判断,让本已多重if-else判断语句更多了,这样的设计显然违背了“开放-*”原则。这时候,我们可以给与职责链模式来解决这样的问题。
二、职责链模式的详细介绍
2.1、动机(Motivate)
在软件构建过程中,一个请求可能被多个东西措置惩罚惩罚,但是每个请求在运行时只能有一个接受者,如果显示指定,将必不成少地带来请求发送者与接受者的紧耦合。如何使请求的发送者不需要指定具体的接受者,让请求的接受者本身在运行时决定来措置惩罚惩罚请求,从而使两者解耦。
2.2、意图(Intent)
制止请求发送者与接收者耦合在一起,让多个东西都有可能接受请求,将这些东西连接成一条链,并且沿着这条链通报请求,知道有东西措置惩罚惩罚它为止。 ——《设计模式》GoF
2.3、布局图(Structure)
2.4、模式的构成
可以看出,在职责链模式的布局图有以下角色:
(1)、抽象措置惩罚惩罚者角色(Handler):抽象措置惩罚惩罚者界说了一个措置惩罚惩罚请求的接口,它一般设计为抽象类,由于差此外具体措置惩罚惩罚者措置惩罚惩罚请求的方法差别,因此在此中界说了抽象请求措置惩罚惩罚要领。因为每一个措置惩罚惩罚者的下家还是一个措置惩罚惩罚者,因此在抽象措置惩罚惩罚者中界说了一个自类型的东西,作为其对下家的引用。通过该引用,措置惩罚惩罚者可以连成一条链。
(2)、具体措置惩罚惩罚者角色(ConcreteHandler):具体措置惩罚惩罚者是抽象措置惩罚惩罚者的子类,它可以措置惩罚惩罚用户请求,在具体措置惩罚惩罚者类中实现了抽象措置惩罚惩罚者中界说的抽象措置惩罚惩罚要领,在措置惩罚惩罚请求之前需要进行判断,看是否有相应的措置惩罚惩罚权限,如果可以措置惩罚惩罚请求就措置惩罚惩罚它,否则将请求转发给后继者;在具体措置惩罚惩罚者中可以访谒链中下一个东西,以便请求的转发。
2.5、职责链模式的代码实现
在现实生活中,职责链模式的例子也是很多的,例如:公司的告假流程就是一个很好的职责链模式的例子,如果告假半天,只要报告本部门经理就可以了;如果告假7天或者以上必需人事总监批准;如果告假15天以上,那就要颠末总裁批准了。还有类似的例子就是采购的流程,其流程也是职责链模式很好的浮现,采购的金额差别,需要批准的人员也差别,好比:部门采购1万元的纸品,只要部门带领签批就可以,如果要采购大于1万小于5万的物品,那就需要财务经理签批了,如果采购30万的原质料或者物品,那就需要总裁或者类似角色才华审批了。接下来我们就以采购的实例来说明职责链模式。实现代码如下:
1 namespace ChainOfResponsibility 2 { 3 // 采购请求 4 public sealed class PurchaseRequest 5 { 6 // 金额 7 public double Amount { get; set; } 8 9 // 产品名字 10 public string ProductName { get; set; } 11 12 public PurchaseRequest(double amount, string productName) 13 { 14 Amount = amount; 15 ProductName = productName; 16 } 17 } 18 19 //抽象审批人,Handler---相当于“抽象措置惩罚惩罚者角色” 20 public abstract class Approver 21 { 22 //下一位审批人,由此形成一条链 23 public Approver NextApprover { get; set; } 24 25 //审批人的名称 26 public string Name { get; set; } 27 28 public Approver(string name) 29 { 30 this.Name = name; 31 } 32 33 //措置惩罚惩罚请求 34 public abstract void ProcessRequest(PurchaseRequest request); 35 } 36 37 //部门经理----相当于“具体措置惩罚惩罚者角色” ConcreteHandler 38 public sealed class Manager : Approver 39 { 40 public Manager(string name): base(name){ } 41 42 public override void ProcessRequest(PurchaseRequest request) 43 { 44 if (request.Amount <= 10000.0) 45 { 46 Console.WriteLine("{0} 部门经理批准了对原质料{1}的采购打算!", this.Name, request.ProductName); 47 } 48 else if (NextApprover != null) 49 { 50 NextApprover.ProcessRequest(request); 51 } 52 } 53 } 54 55 //财务经理---相当于“具体措置惩罚惩罚者角色”ConcreteHandler 56 public sealed class FinancialManager : Approver 57 { 58 public FinancialManager(string name): base(name){ } 59 60 public override void ProcessRequest(PurchaseRequest request) 61 { 62 if (request.Amount > 10000.0 && request.Amount <= 50000.0) 63 { 64 Console.WriteLine("{0} 财务经理批准了对原质料{1}的采购打算!", this.Name, request.ProductName); 65 } 66 else if (NextApprover != null) 67 { 68 NextApprover.ProcessRequest(request); 69 } 70 } 71 } 72 73 //总裁---相当于“具体措置惩罚惩罚者角色” ConcreteHandler 74 public sealed class CEO :Approver 75 { 76 public CEO(string name): base(name){ } 77 78 public override void ProcessRequest(PurchaseRequest request) 79 { 80 if (request.Amount > 50000.0 && request.Amount < 300000.0) 81 { 82 Console.WriteLine("{0} 总裁批准了对原质料 {1} 的采购打算!", this.Name, request.ProductName); 83 } 84 else 85 { 86 Console.WriteLine("这个采购打算的金额对照大,需要一次董事会会议讨论才华决定!"); 87 } 88 } 89 } 90 91 class Program 92 { 93 static void Main(string[] args) 94 { 95 PurchaseRequest requestDao = new PurchaseRequest(8000.0, "单刀5把"); 96 PurchaseRequest requestHuaJi = new PurchaseRequest(10000.0, "10把方天画戟"); 97 PurchaseRequest requestJian = new PurchaseRequest(80000.0, "5把金丝龙鳞闪电劈"); 98 99 Approver manager = new Manager("黄飞鸿"); 100 Approver financial = new FinancialManager("黄麒英"); 101 Approver ceo = new CEO("十三姨"); 102 103 // 设置职责链 104 manager.NextApprover = financial; 105 financial.NextApprover = ceo; 106 107 // 措置惩罚惩罚请求 108 manager.ProcessRequest(requestDao); 109 manager.ProcessRequest(requestHuaJi); 110 manager.ProcessRequest(requestJian); 111 112 Console.ReadLine(); 113 } 114 } 115 }