23种设计模式之责任链模式(Chain of Responsibility Pattern)

责任链模式(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     }
View Code
 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     }
View Code
 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     }
View Code
 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     }
View Code
 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     }
View Code
 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     }
View Code
 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     }
View Code
 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     }
View Code

前端调用:

 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                     //把流程环节逻辑从业务类转移了
View Code
 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     }
View Code

代码中存在多个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

原文地址:https://www.cnblogs.com/Dewumu/p/11451460.html