在现实生活中,常常会出现这样的事例:一个请求有多个对象可以处理,但每个对象的处理条件或权限不同。例如,公司员工请假,可批假的领导有部门负责人、副总经理、总经理等,但每个领导能批准的天数不同,员工必须根据自己要请假的天数去找不同的领导签名,也就是说员工必须记住每个领导的姓名、电话和地址等信息,这增加了难度。这样的例子还有很多,如找领导出差报销、生活中的“击鼓传花”游戏等。

在计算机软硬件中也有相关例子,如总线网中数据报传送,每台计算机根据目标地址是否同自己的地址相同来决定是否接收;还有异常处理中,处理程序根据异常的类型决定自己是否处理该异常;还有Struts2的拦截器、JSP和Servlet的 Filter 等,所有这些,如果用责任链模式都能很好解决。
模式的定义与特点责任链(Chain of Responsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

注意:责任链模式也叫职责链模式。

在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,所以责任链将请求的发送者和请求的处理者解耦了。

责任链模式是一种对象行为型模式,其主要优点如下。

  • 降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
  • 增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
  • 增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
  • 责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
  • 责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

其主要缺点如下。

  • 不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
  • 对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
  • 职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

模式的结构与实现通常情况下,可以通过数据链表来实现职责链模式的数据结构。
1. 模式的结构职责链模式主要包含以下角色。

  • 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
  • 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
  • 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

其结构图如图 1 所示。客户端可按图 2 所示设置责任链。


图1 责任链模式的结构图


图2 责任链

2. 模式的实现职责链模式的实现代码如下:

  • package chainOfResponsibility;
  • publicclassChainOfResponsibilityPattern
  • {
  • publicstaticvoidmain(String[]args)
  • {
  • //组装责任链
  • Handler handler1=newConcreteHandler1();
  • Handler handler2=newConcreteHandler2();
  • handler1.setNext(handler2);
  • //提交请求
  • handler1.handleRequest("two");
  • }
  • }
  • //抽象处理者角色
  • abstractclassHandler
  • {
  • privateHandler next;
  • publicvoidsetNext(Handler next)
  • {
  • this.next=next;
  • }
  • publicHandlergetNext()
  • {
  • returnnext;
  • }
  • //处理请求的方法
  • publicabstractvoidhandleRequest(String request);
  • }
  • //具体处理者角色1
  • classConcreteHandler1 extends Handler
  • {
  • publicvoidhandleRequest(String request)
  • {
  • if(request.equals("one"))
  • {
  • System.out.println("具体处理者1负责处理该请求!");
  • }
  • else
  • {
  • if(getNext()!=null)
  • {
  • getNext().handleRequest(request);
  • }
  • else
  • {
  • System.out.println("没有人处理该请求!");
  • }
  • }
  • }
  • }
  • //具体处理者角色2
  • classConcreteHandler2 extends Handler
  • {
  • publicvoidhandleRequest(String request)
  • {
  • if(request.equals("two"))
  • {
  • System.out.println("具体处理者2负责处理该请求!");
  • }
  • else
  • {
  • if(getNext()!=null)
  • {
  • getNext().handleRequest(request);
  • }
  • else
  • {
  • System.out.println("没有人处理该请求!");
  • }
  • }
  • }
  • }

程序运行结果如下:具体处理者2负责处理该请求!模式的应用实例【例1】用责任链模式设计一个请假条审批模块。

分析:假如规定学生请假小于或等于 2 天,班主任可以批准;小于或等于 7 天,系主任可以批准;小于或等于 10 天,院长可以批准;其他情况不予批准;这个实例适合使用职责链模式实现。

首先,定义一个领导类(Leader),它是抽象处理者,包含了一个指向下一位领导的指针 next 和一个处理假条的抽象处理方法 handleRequest(int LeaveDays);然后,定义班主任类(ClassAdviser)、系主任类(DepartmentHead)和院长类(Dean),它们是抽象处理者的子类,是具体处理者,必须根据自己的权力去实现父类的 handleRequest(int LeaveDays) 方法,如果无权处理就将假条交给下一位具体处理者,直到最后;客户类负责创建处理链,并将假条交给链头的具体处理者(班主任)。图 3 所示是其结构图。


图3 请假条审批模块的结构图

程序代码如下:

  • package chainOfResponsibility;
  • publicclassLeaveApprovalTest
  • {
  • publicstaticvoidmain(String[]args)
  • {
  • //组装责任链
  • Leader teacher1=newClassAdviser();
  • Leader teacher2=newDepartmentHead();
  • Leader teacher3=newDean();
  • //Leader teacher4=new DeanOfStudies();
  • teacher1.setNext(teacher2);
  • teacher2.setNext(teacher3);
  • //teacher3.setNext(teacher4);
  • //提交请求
  • teacher1.handleRequest(8);
  • }
  • }
  • //抽象处理者:领导类
  • abstractclassLeader
  • {
  • privateLeader next;
  • publicvoidsetNext(Leader next)
  • {
  • this.next=next;
  • }
  • publicLeadergetNext()
  • {
  • returnnext;
  • }
  • //处理请求的方法
  • publicabstractvoidhandleRequest(intLeaveDays);
  • }
  • //具体处理者1:班主任类
  • classClassAdviser extends Leader
  • {
  • publicvoidhandleRequest(intLeaveDays)
  • {
  • if(LeaveDays<=2)
  • {
  • System.out.println("班主任批准您请假"+LeaveDays+"天。");
  • }
  • else
  • {
  • if(getNext()!=null)
  • {
  • getNext().handleRequest(LeaveDays);
  • }
  • else
  • {
  • System.out.println("请假天数太多,没有人批准该假条!");
  • }
  • }
  • }
  • }
  • //具体处理者2:系主任类
  • classDepartmentHead extends Leader
  • {
  • publicvoidhandleRequest(intLeaveDays)
  • {
  • if(LeaveDays<=7)
  • {
  • System.out.println("系主任批准您请假"+LeaveDays+"天。");
  • }
  • else
  • {
  • if(getNext()!=null)
  • {
  • getNext().handleRequest(LeaveDays);
  • }
  • else
  • {
  • System.out.println("请假天数太多,没有人批准该假条!");
  • }
  • }
  • }
  • }
  • //具体处理者3:院长类
  • classDean extends Leader
  • {
  • publicvoidhandleRequest(intLeaveDays)
  • {
  • if(LeaveDays<=10)
  • {
  • System.out.println("院长批准您请假"+LeaveDays+"天。");
  • }
  • else
  • {
  • if(getNext()!=null)
  • {
  • getNext().handleRequest(LeaveDays);
  • }
  • else
  • {
  • System.out.println("请假天数太多,没有人批准该假条!");
  • }
  • }
  • }
  • }
  • //具体处理者4:教务处长类
  • classDeanOfStudies extends Leader
  • {
  • publicvoidhandleRequest(intLeaveDays)
  • {
  • if(LeaveDays<=20)
  • {
  • System.out.println("教务处长批准您请假"+LeaveDays+"天。");
  • }
  • else
  • {
  • if(getNext()!=null)
  • {
  • getNext().handleRequest(LeaveDays);
  • }
  • else
  • {
  • System.out.println("请假天数太多,没有人批准该假条!");
  • }
  • }
  • }
  • }

程序运行结果如下:院长批准您请假8天。
假如增加一个教务处长类,可以批准学生请假 20 天,也非常简单,代码如下:

  • //具体处理者4:教务处长类
  • classDeanOfStudies extends Leader
  • {
  • publicvoidhandleRequest(intLeaveDays)
  • {
  • if(LeaveDays<=20)
  • {
  • System.out.println("教务处长批准您请假"+LeaveDays+"天。");
  • }
  • else
  • {
  • if(getNext()!=null)
  • {
  • getNext().handleRequest(LeaveDays);
  • }
  • else
  • {
  • System.out.println("请假天数太多,没有人批准该假条!");
  • }
  • }
  • }
  • }

模式的应用场景前边已经讲述了关于责任链模式的结构与特点,下面介绍其应用场景,责任链模式通常在以下几种情况使用。

  • 有多个对象可以处理一个请求,哪个对象处理该请求由运行时刻自动确定。
  • 可动态指定一组对象处理请求,或添加新的处理者。
  • 在不明确指定请求处理者的情况下,向多个处理者中的一个提交请求。

模式的扩展职责链模式存在以下两种情况。

  • 纯的职责链模式:一个请求必须被某一个处理者对象所接收,且一个具体处理者对某个请求的处理只能采用以下两种行为之一:自己处理(承担责任);把责任推给下家处理。
  • 不纯的职责链模式:允许出现某一个具体处理者对象在承担了请求的一部分责任后又将剩余的责任传给下家的情况,且一个请求可以最终不被任何接收端对象所接收。

责任链模式(职责链模式)详解相关推荐

  1. 《设计模式详解》行为型模式 - 职责链模式

    职责链模式 6.4 职责链模式 6.4.1 概述 6.4.2 结构 6.4.3 案例实现 6.4.4 优缺点 6.4.5 JavaWeb 源码 - FilterChain 完整的笔记目录:<设计 ...

  2. 责任链模式(职责链模式)(Chain of Responsibility Pattern)

    学校OA 系统的采购审批项目:需求是 采购员采购教学器材 如果金额小于等于5000, 由教学主任审批(0<=x<=5000) 如果金额小于等于10000, 由院长审批(5000<x& ...

  3. 15、设计模式-行为型模式-职责链模式

    职责链模式 很多情况下,在一个软件系统中可以处理某个请求的对象不止一个,例如SCM系统中的采购 单审批,主任.副董事长.董事长和董事会都可以处理采购单,他们可以构成一条处理采购 单的链式结构,采购单沿 ...

  4. 区块链用哪种语言 Java_区块链开发用什么语言呢?区块链与编程语言的关系详解...

    原标题:区块链开发用什么语言呢?区块链与编程语言的关系详解 区块链的概念就随着比特币的大热开始逐渐进入公众视野,比特币的拥有者为了使其创造更高的财富,开始疯狂炒作,因而引发购买比特币大浪潮.然而等到比 ...

  5. 我的世界服务器修改飞行速度,我的世界创造模式飞行速度修改教程详解

    这次百度攻略&搞趣网小编为诸位我的世界玩家带来的是我的世界创造模式飞行速度修改教程详解,希望诸位我的世界玩家会喜欢. 我的世界创造模式飞行速度修改教程详解 虽然飞行比走路要快很多,但是在建造大 ...

  6. python的编程模式-Python设计模式之状态模式原理与用法详解

    本文实例讲述了Python设计模式之状态模式原理与用法.分享给大家供大家参考,具体如下: 状态模式(State Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类 ...

  7. 深入剖析Redis系列(三) - Redis集群模式搭建与原理详解

    前言 在 Redis 3.0 之前,使用 哨兵(sentinel)机制来监控各个节点之间的状态.Redis Cluster 是 Redis 的 分布式解决方案,在 3.0 版本正式推出,有效地解决了 ...

  8. 怎样进入android模式,安卓手机如何进入Recovery模式的通用方式详解

    2014-12-12 15:24:16 安卓手机如何进入Recovery模式的通用方式详解 标签:安卓 Recovery模式 教程 Recovery模式是什么?这里说的Recovery模式主要指的是安 ...

  9. android doze模式源码分析,Android Doze模式启用和恢复详解

    从Android 6.0(API level 23)开始,Android提出了两个延长电池使用时间的省电特性给用户.用户管理可以在没有充电的情况下管理app的行为.当用户一段时间没有使用手机的时候,D ...

  10. Java单机部署,Nacos docker单机模式部署实现过程详解

    Nacos 的部署,我使用的时docker 部署(单机模式 mysql),官网文档:https://nacos.io/zh-cn/docs/quick-start-docker.html 拉取代码: ...

最新文章

  1. GeoAnalyticsServer在Linux下集群部署手册
  2. 想做测试经理的看过来
  3. 容器化实践金融业案例一
  4. 黄斑区隆起原因诊断过程+黄斑反复水肿问题
  5. 英特尔表示:元宇宙的路还很长
  6. java 中 的 =,java 中的 |=、=、^=
  7. Matlab运用mapping包在地图上绘制散点图(热力图)
  8. 机器人与目标匹配问题及解决 虚拟动力学 纳什平衡 Q-Learning
  9. 计算机网络学习(七)—集线器与交换机
  10. 《编写高质量代码:改善Python程序的91个建议》读后感
  11. PHP函数strcmp,PHP strcmp函数
  12. PTAM在Linux下编译运行
  13. 嵌入式ARM核心板介绍
  14. 机器学习 泛化误差和偏差-方差
  15. 安卓开发实现悬浮窗显示(全局显示),通过悬浮窗实时监控当前流量
  16. python 将彩色图片 黑白图片变换
  17. 日常小记-pdf扫描版和非扫描版区别
  18. ECL电平特点及其应用
  19. 活动预告|CodeWisdom软件供应链系列学术报告:第5期(鲍凌峰 浙江大学)
  20. vue脚手架引入bootstrap3

热门文章

  1. python stdout_python中stdout输出不缓存的设置方法
  2. 基于PyTorch的遥感影像、无人机影像的地物分类、目标检测、语义分割和点云分类
  3. excel下使用的统计方法(DEA)是非常有用的
  4. 工银e生活开发脱坑日志(8)使用json_decode无法解析json,双引号才是json 的标准
  5. eclipse查java版本_Eclipse中如何查看当前使用的JDK版本?
  6. influxdb+grafana+jmeter教程
  7. 使用dom4j解析xml_使用dom4j解析XML
  8. 抖音直播运营分析必备工具!千川投放提高付费流量转化ROI
  9. iOS复选框——高雅的BEMCheckBox
  10. HTML5 SVG卡通水母动画代码