• 设计模式——责任链模式


    责任链模式的定义

    责任链模式又称职责链模式,是一种行为型设计模式。官方描述:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

    原文链接或文中示例代码下载,请关注公众号【Qin的学习营地】,回复:【责任链模式

    场景示例

    上述定义是对责任链模式这种思想的归纳总结,理解起来稍微抽象,下面结合一种场景逐步深入责任链模式。

    企业采购

    在企业中经常需要采购一些物品,小到一些廉价的生活用品,大到昂贵的精密器械,采购金额高低各异,不同采购金额需要由不同领导层次的管理人审批。比如金额在1万以下的只需部门负责人审批即可;金额超过1万且10万以下,部门负责人无权审批,需交由总经理审批;金额超过10万以上则只能层层上报到董事长,由董事长审批了,如下图。
    在这里插入图片描述

    简单的 if…else 实现方案

    在上述企业采购中,采购金额不同分别交由不同层次的领导审批,这里最简单的实现方案就是使用 if…else 判断。代码如下:

    // 采购审批处理类
    public class PurchaseHandler {
    
        // 采购审批处理方法
        public String handleRequest(String purchaserName, Double purchaseAmount){
            if (purchaseAmount < 10000.0){ // 部门负责人审批
                return approvalByDepartmentLeader(purchaserName, purchaseAmount);
            } else if (purchaseAmount < 100000.0) { // 总经理审批
                return approvalByManager(purchaserName, purchaseAmount);
            } else { // 董事长审批
                return approvalByChairman(purchaserName, purchaseAmount);
            }
        }
    
        private String approvalByDepartmentLeader(String purchaserName, Double purchaseAmount){
            return (purchaserName + "申请采购金额:" + purchaseAmount + "元, 审批人:部门负责人");
        }
    
        private String approvalByManager(String purchaserName, Double purchaseAmount){
            return (purchaserName + "申请采购金额:" + purchaseAmount + "元, 审批人:总经理");
        }
    
        private String approvalByChairman(String purchaserName, Double purchaseAmount){
            return (purchaserName + "申请采购金额:" + purchaseAmount + "元, 审批人:董事长");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    if…else 实现方案存在的问题

    分析 if…else 实现方案存在的问题:

    1. 代码结构不够清晰干净。
    2. 采购审批中的每个审批环节可能存在业务逻辑改动,比如部门负责人审核完之后,还是总经理签字,这就需要修改审批处理类和方法。
    3. 采购审批流程发生变化,当金额超过一定数额时,也不能完全由董事长审批,需要通过董事会投票决定,这就需要增加一个审批步骤,同样也需要修改源代码。

    责任链模式实现方案

    仔细分析上面的场景,客户端提出一个采购申请请求,对于客户端来说,他不需要关心是谁审批,后续审批流上可能是由部门负责人、总经理、董事长任一符合方进行审批。这样从部门负责人到总经理、再到董事长审批流程,可以看作是一条链,客户端提出的申请请求在这个链上传递,直到对应的责任人审批为止。

    流程中可能在任意位置新增环节,每个环节可能会修改自己的处理逻辑,为了方便修改或复用每个环节;或者扩展新增环节,组合不同流程,可以将每个环节作为一个单独的对象,并且只实现单一的处理功能,这样细粒度划分功能,有利于降低修改的影响面和提高扩展性。

    责任链模式概念

    责任链模式就体现了上述细粒度抽取的思想,核心在于引入了一个抽象处理者。

    责任链模式结构图:
    在这里插入图片描述

    责任链模式中的角色:

    • Handler(抽象处理者):一个处理请求的接口,一般设计为抽象类,其中定义一个处理请求的抽象方法,不同的具体处理者实现该方法;每个处理者可能需要将请求传递给下一个处理者,所以还可以定义一个处理者对象,作为后继者的引用,从而实现一条链。

    • ConcreteHandler(具体处理者):抽象处理者的具体实现子类,实现抽象处理类中的抽象方法,方法需要实现的两个功能:一是处理请求,处理具体处理者职责范围内的请求;二是转发请求,不在该具体处理者职责范围内的请求,就将请求转发给后继者处理。

    • Client(客户端):责任链客户端,组合处理者对象构造责任链,同时请求责任链处理请求对象。

      组合的顺序很重要,如果顺序不对,处理的结果可能就不是符合要求的。

      Client 不算责任链中的角色,外部使用责任链模式时自行创建。

    责任链模式代码示例:

    1、定义抽象处理者接口类,类中持有下一个处理者对象,同时实现请求处理方法:

    // 定义责任链抽象接口类
    public abstract class Handler {
    
        // 持有下一个处理者对象引用
        protected Handler nextHandler;
    
        // 设置下一个处理者对象
        public void setNextHandler(Handler nextHandler) {
            this.nextHandler = nextHandler;
        }
    
        // 处理采购申请请求
        public abstract String handleRequest(String purchaserName, Double purchaseAmount);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    2、实现具体处理者类,实现处理请求的具体方法,方法内部逻辑:处理请求的具体逻辑,或者将请求对象传递给下一个处理者。这里实现三个具体处理者。

    • DepartmentLeaderHandler 部门负责人处理类

      // 部门负责人处理类
      public class DepartmentLeaderHandler extends Handler {
          @Override
          public String handleRequest(String purchaserName, Double purchaseAmount) {
              // 职责范围内处理审批请求
              if (purchaseAmount < 10000){
                  return (purchaserName + "申请采购金额:" + purchaseAmount + "元, 审批人:部门负责人");
              } else {
                  // 职责范围外处理,交由下一个处理者处理
                  if (this.nextHandler != null){
                      return this.nextHandler.handleRequest(purchaserName, purchaseAmount);
                  }
              }
              return null;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
    • ManagerHandler 总经理处理类

      // 总经理处理类
      public class ManagerHandler extends Handler {
          @Override
          public String handleRequest(String purchaserName, Double purchaseAmount) {
              // 职责范围内处理审批请求
              if (purchaseAmount < 100000){
                  return (purchaserName + "申请采购金额:" + purchaseAmount + "元, 审批人:总经理");
              } else {
                  // 职责范围外处理,交由下一个处理者处理
                  if (this.nextHandler != null){
                      return this.nextHandler.handleRequest(purchaserName, purchaseAmount);
                  }
              }
              return null;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
    • ChairmanHandler 董事长处理类

      // 董事长处理类
      public class ChairmanHandler extends Handler {
          @Override
          public String handleRequest(String purchaserName, Double purchaseAmount) {
              // 职责范围内处理审批请求
              if (purchaseAmount >= 100000){
                  return (purchaserName + "申请采购金额:" + purchaseAmount + "元, 审批人:董事长");
              } else {
                  // 职责范围外处理,交由下一个处理者处理
                  if (this.nextHandler != null){
                      return this.nextHandler.handleRequest(purchaserName, purchaseAmount);
                  }
              }
              return null;
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16

    3、客户端组合处理者构建责任链并调用

    public class Client {
    
        public static void main(String[] args) {
            // 创建责任链上的每个处理者对象
            DepartmentLeaderHandler departmentLeaderHandler = new DepartmentLeaderHandler();
            ManagerHandler managerHandler = new ManagerHandler();
            ChairmanHandler chairmanHandler = new ChairmanHandler();
    
            // 组合处理者对象构造责任链
            departmentLeaderHandler.setNextHandler(managerHandler);
            managerHandler.setNextHandler(chairmanHandler);
    
            // 提交请求,调用责任链,调用责任链第一个处理者对象即可
            String result = departmentLeaderHandler.handleRequest("采购人员", 105000.0);
            System.out.println(result);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    当调用责任链处理请求时,并不知道谁会真正处理请求,只知道将请求提交到第一个处理者对象。从第一个处理者对象开始,整个责任链中的对象,要么自己处理请求,要么继续转发给下一个接收者。

    从 if…else 判断到责任链模式的使用可以看出,代码结构变得清晰了。 责任链模式很好的满足了单一职责和开闭原则。

    在责任链模式中,可能没有合适的处理者,请求不一定会被处理,所以可以在最后加上不支持处理该请求的提示。

    责任链模式扩展

    责任链构建方式

    责任链构建方式多种多样,现在总结三种基本的实现方式:

    1、客户端在提交请求前组合处理者构造责任链,即在使用的时候动态组合链。如前面责任链的实现就是这种。

    2、可以在抽象处理者 Handler 内部实现责任链的组合。

    3、由各个具体处理者自己决定后继者,这种方式要求每个处理者了解业务流程。

    纯与不纯的责任链

    纯的责任链模式

    • 纯的责任链模式的每个处理者对象只会做两件事,要么处理请求并返回,要么将请求传递给链上的下一个处理者对象。

    不纯的责任链模式

    • 不满足纯的责任链模式要求的就是不纯的责任链,也可以称为功能链。一个请求在责任链中传递,每个处理者对象负责处理请求的某一方面的功能,处理完成后,不是停止,而是继续向后继者传递请求,后继者可以继续处理该请求。
    • 在实际应用开发中,进行业务处理之前,通常需要进行权限检查、通用数据校验、数据逻辑校验等处理,然后才开始真正的业务逻辑实现。可以把这些功能分散到一个功能链中。这样做的目的是使程序结构更加灵活,而且复用性会更好。比如通用的权限检查只需要做一份,然后就可以在多个功能链中使用了。

    责任链模式的优缺点

    优点:

    1. 请求者和处理者松散耦合

      在责任链模式中,请求者并不知道接收者是谁,也不知道具体如何处理,请求者只是负责向责任链发出请求就可以了。而每个处理者对象也不用管请求者或者是其他的处理者对象,只负责处理自己的部分,其他的就交给其他的处理者对象去处理。并且链中的对象不需要知道链的结构,可以由客户端负责链的创建,降低耦合。

    2. 动态组合

      责任链模式会把功能处理分散到单独的处理者对象中,然后在使用的时候,可以动态组合处理者形构造责任链,从而可以灵活地给对象分配职责,也可以灵活地实现和改变对象的职责。

    3. 符合开闭原则

      在系统中新增具体处理者对象时无需修改原代码,只需要在客户端重新构建责任链即可。

    缺点:

    1. 产生很多细粒度对象

      责任链模式会把功能处理分散到单独的处理者对象中,也就是每个处理者对象只处理一个方面的功能,要把整个业务处理完,需要很多处理者对象的组合,这样会产生大量的细粒度处理者对象。

    2. 不一定能被处理

      责任链模式的每个处理者对象只负责自己处理的那一部分,因此可能会出现某个请求,把整个链传递完了,都没有处理者对象处理它。这就需要在使用责任链模式的时候,需要提供默认的处理,并且注意构建的链的有效性。

    3. 责任链模式可能会带来一些额外的性能损耗,因为它每次执行请求都要从链子开头开始遍历。甚至责任链构建不当,出现循环调用,导致系统陷入死循环。

    责任链模式在框架源码中的应用

    完整后续内容请关注公众号【Qin的学习营地】,回复:【责任链模式

  • 相关阅读:
    mysql自带的性能测试工具mysqlslap执行压力测试
    TestOps、TestDev
    基于JAVA医院远程诊断系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    JVM小测
    【ORACLE】ORA-00972:标识符过长
    不同温度与工况的放电曲线与内阻曲线
    C#西门子S7 协议通过偏移量的方式读写PLC DB块
    双向不带头链表 —— Java(附有源码)
    立创EDA仿真入门2 实战全桥整流
    C#/VB.NET 创建PDF/UA文件
  • 原文地址:https://blog.csdn.net/longool/article/details/134488374