职责链模式(Chain of Responsibility Pattern)

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/130 访问。

职责链模式属于行为型模式,它为请求创建了一个接收者对象的链。这种模式给予一个具体请求的类型,对请求的发送者和接收者进行解耦。

通常有2种方法来实现该模式。第1种是每个接收者都包含对下一个接收者的引用,以便在不能处理该请求时,转派请求至下一个接收者。第2个方法是引入中间链条类,由中间件负责转派请求。第一种方法的实现较为简单,本例采用第2种实现方式。

角色:

1、抽象处理者(Handler)

定义出一个处理请求的接口。接口可以定义出一个方法以设定和返回对链条中下一个处理者的引用,如果使用第2种方式实现,可无需引用下一个处理者,统一由中间件负责;

2、具体处理者(Concrete Handler)

具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家;

3、请求类(Request)

处理者需要处理的请求信息;

4、中间链条类(Chain)

若使用第2种方式实现,则需要引入此中间类,内部维护所有处理者,并在需要时自动转派请求至下一个处理者。

示例:

命名空间ChainOfResponsibility包含领导Leader类充当处理者基类,它包含4个实现类,经理类Manager、总监类Inspector、总经理类President和董事Directorate类,请假信息LeaveRequest类充当请求类,LeaderChain类充当中间链条类。本案例尝试以员工请假来解释职责链模式在审批环节的应用。

namespace ChainOfResponsibility
public class LeaveRequest {public int Days { get; set; }public string Name { get; set; }public LeaveRequest(int days, string name) {Days = days;Name = name;}}

请假请求LeaveRequest类,包含需要请假的天数和员工的姓名。一个公开的构造函数表明调用方必须提供请假天数和员工姓名信息。

public abstract class Leader {protected string Name { get; set; }protected Leader(string name) {this.Name = name;}public static LeaderChain Chain { protected get; set; }public abstract void ProcessRequest(LeaveRequest request);protected void Delivery(LeaveRequest request) {Chain.DoChain(request);}}

领导者Leader类,充当处理者基类,包含领导的姓名Name并维持对中间链的引用。ProcessRequest为处理请假的抽象方法,为处理请假公开了一个调用接口。Delivery则为在不能处理请求时转派至下一个处理者。

public class Manager : Leader {public Manager(string name) : base(name) { }public override void ProcessRequest(LeaveRequest request) {if (request.Days <= 2) {Console.WriteLine($"{this.Name} approved {request.Name}'s " +$"leave request for {request.Days} days!");return;}Delivery(request);}}

具体处理者,经理Manager类,如果员工的请假天数小于等于2天,则经理有权限批准该请假请求。

public class Inspector : Leader {public Inspector(string name) : base(name) { }public override void ProcessRequest(LeaveRequest request) {if (request.Days <= 4) {Console.WriteLine($"{this.Name} approved {request.Name}'s " +$"leave request for {request.Days} days!");return;}Delivery(request);}}

具体处理者,总监Inspector类,如果员工的请假天数小于等于4天,则总监有权限批准该请假请求。

public class President : Leader {public President(string name) : base(name) { }public override void ProcessRequest(LeaveRequest request) {if (request.Days <= 8) {Console.WriteLine($"{this.Name} approved {request.Name}'s " +$"leave request for {request.Days} days!");return;}Delivery(request);}}

具体处理者,总经理President类,如果员工的请假天数小于等于8天,则总经理有权限批准该请假请求。

public class Directorate : Leader {public Directorate(string name) : base(name) { }public override void ProcessRequest(LeaveRequest request) {if (request.Days > 8) {Console.WriteLine($"{this.Name} approved {request.Name}'s " +$"leave request for {request.Days} days!");return;}Delivery(request);}}

具体处理者,董事Directorate类,如果员工的请假天数大于8天,则需要董事会批准该请假请求。

public class LeaderChain {private List<Leader> _leaders = new List<Leader>();private int _cursor = 0;public void Attach(Leader leader) {if (leader == null) throw new ArgumentNullException();_leaders.Add(leader);}public bool Detach(Leader leader) {if (leader == null) throw new ArgumentNullException();return _leaders.Remove(leader);}public void DoChain(LeaveRequest request) {if (_cursor <= _leaders.Count - 2) {_leaders[++_cursor].ProcessRequest(request);}_cursor = 0;}}

中间链条类LeaderChain,首先内部维持对所有处理者的引用,包含的游标_cursor指示链条所处的位置,Attach和Detach方法分别向链条中增加和删除处理者。而DoChain方法则真正转派请求至下一个处理者。

此处需要注意的是,由于请求信息是由第一个处理者直接调用的,所以初始游标位置为0并且在DoChain方法中使用++_cursor作为处理者列表的索引参数。也就是说当第一次转派请求时,索引的值为1(因为使用了++_cursor),即为链条中的第2个处理者。请各位看官仔细思考此处逻辑。

public class Program {public static void Main(string[] args) {var leaders = new List<Leader>{new Manager("Tom"),new Inspector("Juice"),new President("Iori"),new Directorate("Marin")};var chain = new LeaderChain();foreach (var leader in leaders) {chain.Attach(leader);}Leader.Chain = chain;var requests = new List<LeaveRequest> {new LeaveRequest(1, "Zhao"),new LeaveRequest(3, "Qian"),new LeaveRequest(5, "Sun"),new LeaveRequest(7, "Li"),new LeaveRequest(12, "Zhou")};foreach (var request in requests) {leaders[0].ProcessRequest(request);}Console.ReadKey();}}

以上为调用方代码的示例,首初始化一个处理者列表并增加至中间链条类,之后模拟“赵、钱、孙、李、周”5位同学的请假请求,他们分别要请1、3、5、7、12天假,最后调用ProcessRequest处理请求。以下是这个案例的输出结果:

Tom approved Zhao's leave request for 1 days!
Juice approved Qian's leave request for 3 days!
Iori approved Sun's leave request for 5 days!
Iori approved Li's leave request for 7 days!
Marin approved Zhou's leave request for 12 days!

优点:

该文章的最新版本已迁移至个人博客【比特飞】,单击链接 https://www.byteflying.com/archives/130 访问。

1、降低耦合度,它将请求的发送者和接收者解耦;
2、简化了对象,使得对象不需要知道链的结构;
3、增强给对象指派职责的灵活性,通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任;
4、增加新的请求处理者类很方便。

缺点:

1、不能保证请求一定被接收;
2、系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用;
3、可能不容易观察运行时的特征,不利于程序的调试。

使用场景:

1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时确定;
2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;
3、需要动态指定一组对象处理请求。

C#设计模式之13-职责链模式相关推荐

  1. OOP设计模式[JAVA]——03职责链模式

    职责链模式 Responsibility of Chain 在职责链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求 ...

  2. 《研磨设计模式》chap23 职责链模式chainOfResponsibility(3)功能扩展+总结

    1. 扩展 功能链:某个链处理完继续向下传递. public class SaleModel {//销售的商品 private String goods;public String getGoods( ...

  3. JS设计模式五:职责链模式

    职责链模式简述 职责连是由多个不同的对象组成的,有发送者跟接收者,分别负责信息的发送跟接收,其中,链中第一个对象是 职责连是由多个不同的对象组成的,发送者是发送请求的对象,接收者接收请求并且对其进行处 ...

  4. JAVA设计模式之【职责链模式】

    职责链模式专门处理请求链式传递的模式角色Handler抽象处理者ConcreteHandler具体处理者在职责链模式中,很多对象由每一个对象对其下家的引用而连接成一条链,请求在这条链上传递,直到链上的 ...

  5. 王争 | 设计模式之美 - 职责链模式

    文章目录 1. 职责链模式的定义 2. 职责链模式的代码实现方式1 1. 处理器抽象类 Handler 2. 具体处理器 HandlerA 和 HandlerB 3. 处理器链 HandlerChai ...

  6. 《研磨设计模式》chap23 职责链模式chainOfResponsibility(1)模式简介

    场景:申请经费,有好几个领导审批,项目经理.部门经理.总经理,最后总会有一个人回复审批结果. 1. 正常编码 public class FeeRequest {//提交聚餐费用申请给项目经理 publ ...

  7. 《研磨设计模式》chap23 职责链模式chainOfResponsibility(2)应用场景

    1. 初步实现 public abstract class Handler {//持有下一个处理请求的对象 protected Handler successor = null;//设置下一个处理请求 ...

  8. JBPM与设计模式之职责链模式

    上篇我们了解并学习了JBPM的长事务实现,其中用到了设计模式中的职责链模式和命令模式:这块还是很有厚重感的,我们可以从中学到很多的东西:今天我们先来学习一下职责链模式. 职责链模式定义 使多个对象都有 ...

  9. 职责链模式之真假美猴王

    孙悟空最终还是没有能逃脱如来的手掌心,因缘注定,皈依佛门,虽没有了做齐天大圣是的逍遥快活,也没有大闹天宫时的轰轰烈烈,但是现在有了更重要的一项任务,那就是普度众生,< 西游记>第五十七回, ...

  10. 设计模式之职责链模式(Chain of Responsibility)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...

最新文章

  1. 【转载】目前为止看到描述VSCode编写C++配置文件最清楚的一篇文章
  2. Mysql定期自动备份
  3. Scikit-learn 数据预处理之标准化StandardScaler
  4. MaintainableCSS 《可维护性 CSS》 --- 模板篇
  5. 高端智能阿里手机 黑色 ZOPO C2 出售1499
  6. lynda ux_UX编排原理
  7. spring-boot-starter-parent的主要作用
  8. 解决Ubuntu 9.04无线网络的不稳定问题-转
  9. 单核工作法图解:事多到事少,拖延变高效
  10. 单片机和嵌入式设计的区别
  11. 免费数字证书申请(https)
  12. P4556 雨天的尾巴 线段树合并
  13. 【寻找最佳小程序】11期:车来了——时时公交就在你身边,到站准确率可控制在90%以上...
  14. 28岁华为员工工资表曝光,牛逼的人注定会牛逼​!
  15. 北京办理互联网经营许可证(ICP证)的要求
  16. 基于SpringBoot + Vue的个人博客系统12——使用vue-admin-template展示文章列表(后台管理)
  17. WinRAR的 安装与下载
  18. unhandled exception in XXX:0xC0000005:access violation问题
  19. 搭建DVWA出现错误:DVWA System error - config file not found.
  20. 手机APP界面设计尺寸笔记

热门文章

  1. Ubuntu 16.04 开机自动锁定数字键盘
  2. 2020-python小工能
  3. git-对比不同-版本与文件的对比,版本与版本的对比
  4. openssh升级后无法登陆解决方案
  5. 深度访谈Amazon员工与HR:华裔因pip跳楼背后(图)
  6. 趣图:产品还没测试直接投入生产时
  7. (原創) 如何将字符串前后的空白去除? (使用string.find_first_not_of, string.find_last_not_of) (C/C++)...
  8. 枚举项的数量限制在64个以内
  9. python 中的面向对象
  10. Redhat 7 Web服务器配置