23.java设计模式之责任链模式

基本需求

  • 采购员采购教学器材
    • 如果金额小于等于5000,由教学主任审批(0<=x<=5000)
    • 如果金额小于等于10000,由教学主任审批(5000<x<=10000)
    • 如果金额小于等于30000,由教学主任审批(10000<x<=30000)
    • 如果金额超过30000,由教学主任审批(30000<x)

传统方案

  • 传统方案是:接收到一个采购请求之后,根据采购的金额来调用对应的审批人完成审批
    • 客户端这里会使用分值判断比如(if)来对不同的采购请求处理,这样就存在
      • 如果各个级别的人员审批金额发生变化,在客户端的也需要变化
      • 客户端必须明确的知道,有多少个审批级别和访问
    • 对一个采购请求进行处理和审批人就存在强耦合关系,不利于代码的扩展和维护
    • 可使用责任链模式解决

基本介绍

  • 责任链(Chain of Responsiblility)模式,又叫职责链模式,为请求创建了一个接收者对象的链,这种模式对请求的发送者和接收者进行解耦

  • 责任链模式通常每个接收者都包含另一个接收者的引用,如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,以此类推

  • 这种设计模式属于行为型模式

  • UML类图(原理)

    • 说明

      • Handler:抽象的处理者,定义一个处理请求的接口,同时含有另一个Handler
      • ConcreteHandlerA和B:具体的处理者,处理它自己负责的请求,可以访问它的后继者(即下一个处理者),如果可以处理当前的请求则处理,否则就将该请求交给后继者去处理,从而形成一个职责链
      • Request:含有多个属性,表示一个请求
  • UML类图(案例)

  • 代码实现

    • // 请求类
      @Data
      @AllArgsConstructor
      public class PurchaseRequest {
      
         // 请求类型
         private Integer type;
      
         // id
         private Integer id;
      
         // 请求的价格
         private Float price;
      }
      
    • // 处理请求的抽象父类
      public abstract class Approve {
      
         // 处理者名称
         protected String name;
      
         // 下一个处理者
         protected Approve nextApprove;
      
         public Approve(String name) {
             this.name = name;
         }
      
         // 处理请求的抽象方法
         public abstract void processApprove(PurchaseRequest purchaseRequest);
      
         public void setNextApprove(Approve nextApprove) {
             this.nextApprove = nextApprove;
         }
      }
      
      // 子类一 教学主任审批
      class DepartmentApprover extends Approve{
      
         public DepartmentApprover(String name) {
             super(name);
         }
      
         @Override
         public void processApprove(PurchaseRequest purchaseRequest) {
             if (null != purchaseRequest) {
                 if (purchaseRequest.getPrice() <= 5000) {
                     System.out.println(" 请求编号 id = " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
                 } else {
                     // 使用下一个处理者处理
                     this.nextApprove.processApprove(purchaseRequest);
                 }
             }
         }
      }
      
      // 子类二 院长审批
      class CollegeApprover extends Approve{
      
         public CollegeApprover(String name) {
             super(name);
         }
      
         @Override
         public void processApprove(PurchaseRequest purchaseRequest) {
             if (null != purchaseRequest) {
                 if (purchaseRequest.getPrice() > 5000 && purchaseRequest.getPrice() <= 10000) {
                     System.out.println(" 请求编号 id = " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
                 } else {
                     // 使用下一个处理者处理
                     this.nextApprove.processApprove(purchaseRequest);
                 }
             }
         }
      }
      
      // 子类三 副校长审批
      class ViceSchoolMasterApprover extends Approve{
      
         public ViceSchoolMasterApprover(String name) {
             super(name);
         }
      
         @Override
         public void processApprove(PurchaseRequest purchaseRequest) {
             if (null != purchaseRequest) {
                 if (purchaseRequest.getPrice() > 10000 && purchaseRequest.getPrice() <= 30000) {
                     System.out.println(" 请求编号 id = " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
                 } else {
                     // 使用下一个处理者处理
                     this.nextApprove.processApprove(purchaseRequest);
                 }
             }
         }
      }
      
      // 子类四 校长审批
      class SchoolMasterApprover extends Approve{
      
         public SchoolMasterApprover(String name) {
             super(name);
         }
      
         @Override
         public void processApprove(PurchaseRequest purchaseRequest) {
             if (null != purchaseRequest) {
                 if (purchaseRequest.getPrice() > 30000) {
                     System.out.println(" 请求编号 id = " + purchaseRequest.getId() + " 被 " + this.name + " 处理");
                 } else {
                     // 使用下一个处理者处理
                     this.nextApprove.processApprove(purchaseRequest);
                 }
             }
         }
      }
      
    • public class Client {
         public static void main(String[] args) {
             // 创建各个级别的审批人
             DepartmentApprover departmentApprover = new DepartmentApprover("DepartmentApprover");
             CollegeApprover collegeApprover = new CollegeApprover("CollegeApprover");
             ViceSchoolMasterApprover viceSchoolMasterApprover = new ViceSchoolMasterApprover("ViceSchoolMasterApprover");
             SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("SchoolMasterApprover");
             // 使用setXxx方法将各个级别的审批人联系起来
             // 此次使用环状(首尾相连,请求可从任意一个级别进入,处理的条件需要实现闭环,否则会出现死循环,一直处理不了栈溢出 StackOverflowError)
             // 也可使用链状(首尾不相连,请求从首级别进入,直至最后一级,最后一级也处理不了,就会返回错误)
             departmentApprover.setNextApprove(collegeApprover);
             collegeApprover.setNextApprove(viceSchoolMasterApprover);
             viceSchoolMasterApprover.setNextApprove(schoolMasterApprover);
             schoolMasterApprover.setNextApprove(departmentApprover);
             // 创建请求并处理
             collegeApprover.processApprove(new PurchaseRequest(1, 1, 50000f));
         }
      }
      
      

springmvc源码

  • 在springmvc的HandlerExecutionChain中就是用到了责任链模式

注意事项

  • 将请求和处理分开,实现解耦,提高系统的灵活性
  • 简化了对象,使对象不需要知道链的结构
  • 性能会受到影响,特别是在链较长时,因此需控制链中最大节点数量,一般通过在Handler中设置一个最大节点数量,在setNext()方法中判断是否已经超过阈值,超过则不允许该链建立,避免出现超长链无意识的破坏系统性能
  • 调试不方便,采用了类似递归的方式,调试时逻辑可能比较复杂
  • 最佳应用场景:有多个对象可以处理同一个请求时,例如:多级请求、请假/加薪等审批流程、JavaWeb中Tomcat对Encoding的处理、拦截器
posted @ 2021-02-07 10:23  xiaokantianse  阅读(98)  评论(0编辑  收藏  举报