责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了
优点: 1、降低耦合度。它将请求的发送者和接收者解耦。 2、简化了对象。使得对象不需要知道链的结构。 3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 4、增加新的请求处理类很方便。
缺点: 1、不能保证请求一定被接收。 2、在找到正确的处理对象之前,所有的条件判定都要执行一遍,当责任链过长时,可能会引起性能的问题。 3、可能不容易观察运行时的特征,有碍于除错。
应用实例: 1、JS 中的事件冒泡。2、在现实生活中,有很多请求并不是一个人说了就算的,例如面试时的工资,低于1万的薪水可能技术经理就可以决定了,但是1万~1万5的薪水可能技术经理就没这个权利批准,可能就需要请求技术总监的批准,所以在面试的完后,经常会有面试官说,你这个薪水我这边觉得你这技术可以拿这个薪水的,但是还需要技术总监的批准等的话。
主要涉及两个角色:
- 抽象处理者角色(Handler):定义出一个处理请求的接口。这个接口通常由接口或抽象类来实现。
- 具体处理者角色(ConcreteHandler):具体处理者接受到请求后,可以选择将该请求处理掉,或者将请求传给下一个处理者。因此,每个具体处理者需要保存下一个处理者的引用,以便把请求传递下去
实现代码:
1 public abstract class AbstractAuditor 2 { 3 public string Name { get; set; } 4 public abstract void Audit(ApplyContext context); 5 6 private AbstractAuditor _NextAuditor = null; 7 public void SetNext(AbstractAuditor auditor) 8 { 9 this._NextAuditor = auditor; 10 } 11 protected void AuditNext(ApplyContext context) 12 { 13 if (this._NextAuditor != null) 14 { 15 this._NextAuditor.Audit(context); 16 } 17 else 18 { 19 context.AuditResult = false; 20 context.AuditRemark = "不允许请假!"; 21 } 22 } 23 }
1 /// <summary> 2 /// 请假申请, 3 /// Context--上下文环境,保存业务处理中参数-中间结果-最终结果 4 /// 行为型设计模式常用的标配 5 /// 把行为转移, 6 /// </summary> 7 public class ApplyContext 8 { 9 public int Id { get; set; } 10 public string Name { get; set; } 11 /// <summary> 12 /// 请假时长 13 /// </summary> 14 public int Hour { get; set; } 15 public string Description { get; set; } 16 public bool AuditResult { get; set; } 17 public string AuditRemark { get; set; } 18 }
1 /// <summary> 2 /// 职责问题: 3 /// 1 权限范围内,审批通过 4 /// 2 权限范围外,交给下一环节审批 5 /// 写的代码又多了一个,指定下一环节 6 /// 甩锅大法 7 /// </summary> 8 public class PM : AbstractAuditor 9 { 10 public override void Audit(ApplyContext context) 11 { 12 Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit"); 13 if (context.Hour <= 8) 14 { 15 context.AuditResult = true; 16 context.AuditRemark = "允许请假!"; 17 } 18 else 19 { 20 base.AuditNext(context); 21 } 22 } 23 }
1 public class Charge: AbstractAuditor 2 { 3 public override void Audit(ApplyContext context) 4 { 5 Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit"); 6 if (context.Hour <= 16) 7 { 8 context.AuditResult = true; 9 context.AuditRemark = "允许请假!"; 10 } 11 else 12 { 13 base.AuditNext(context); 14 } 15 } 16 }
1 public class Manager : AbstractAuditor 2 { 3 public override void Audit(ApplyContext context) 4 { 5 Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit"); 6 if (context.Hour <= 24) 7 { 8 context.AuditResult = true; 9 context.AuditRemark = "允许请假!"; 10 } 11 else 12 { 13 base.AuditNext(context); 14 } 15 } 16 }
1 public class Chief : AbstractAuditor 2 { 3 public override void Audit(ApplyContext context) 4 { 5 Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit"); 6 if (context.Hour <= 48) 7 { 8 context.AuditResult = true; 9 context.AuditRemark = "允许请假!"; 10 } 11 else 12 { 13 base.AuditNext(context); 14 //.... 15 } 16 } 17 }
1 public class CEO : AbstractAuditor 2 { 3 public override void Audit(ApplyContext context) 4 { 5 Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit"); 6 if (context.Hour <= 96) 7 { 8 context.AuditResult = true; 9 context.AuditRemark = "允许请假!"; 10 } 11 else 12 { 13 base.AuditNext(context); 14 //.... 15 } 16 } 17 }
1 public class ChiarMan : AbstractAuditor 2 { 3 public override void Audit(ApplyContext context) 4 { 5 Console.WriteLine($"This is {this.GetType().Name} {this.Name} Audit"); 6 if (context.Hour <= 1000000) 7 { 8 context.AuditResult = true; 9 context.AuditRemark = "允许请假!"; 10 } 11 else 12 { 13 base.AuditNext(context); 14 //.... 15 } 16 } 17 }
前端调用:
1 ApplyContext context = new ApplyContext() 2 { 3 Id = 1, 4 Name = "aaa", 5 Hour = 100, 6 Description = "我想...", 7 AuditResult = false, 8 AuditRemark = "" 9 }; 10 //流程的可扩展 11 12 AbstractAuditor auditor = AuditorBuilder.Build(); 13 auditor.Audit(context); 14 if (!context.AuditResult) 15 { 16 Console.WriteLine("不干了!"); 17 } 18 //把流程环节逻辑从业务类转移了
1 public class AuditorBuilder 2 { 3 /// <summary> 4 /// 那就反射+配置文件 5 /// 链子的组成都可以通过配置文件 6 /// </summary> 7 /// <returns></returns> 8 public static AbstractAuditor Build() 9 { 10 AbstractAuditor pm = new PM() 11 { 12 Name = "bbb" 13 }; 14 AbstractAuditor charge = new Charge() 15 { 16 Name = "ccc" 17 }; 18 AbstractAuditor manager = new Manager() 19 { 20 Name = "ddd" 21 }; 22 AbstractAuditor chief = new Chief() 23 { 24 Name = "eee" 25 }; 26 AbstractAuditor ceo = new CEO() 27 { 28 Name = "fff" 29 }; 30 31 pm.SetNext(charge); 32 charge.SetNext(manager); 33 //pm.SetNext(manager); 34 manager.SetNext(chief); 35 chief.SetNext(ceo); 36 ceo.SetNext(new ChiarMan() 37 { 38 Name = "ggg" 39 }); 40 return pm; 41 } 42 }
代码中存在多个if-else语句的情况下,此时可以考虑使用责任链模式来对代码进行重构
本文参考文档:
https://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html
https://www.cnblogs.com/zhili/p/ChainOfResponsibity.html
https://www.cnblogs.com/abcdwxc/archive/2007/09/25/905622.html