zoukankan      html  css  js  c++  java
  • 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的处理、拦截器
  • 相关阅读:
    Blender 3DOne
    [翻译]XNA外文博客文章精选之sixteen(中)
    实习技术员的基本功(二)
    [翻译]XNA外文博客文章精选之fifteen
    实习技术员的基本功(三)
    [翻译]XNA外文博客文章精选之sixteen(下)
    实习技术员的基本功(一)
    [翻译]XNA外文博客文章精选之sixteen(上)
    思维导图
    MySQL error 1045(28000): Access denied for user ...
  • 原文地址:https://www.cnblogs.com/xiaokantianse/p/14384098.html
Copyright © 2011-2022 走看看