您现在的位置是:首页 >学无止境 >设计模式-责任链模式网站首页学无止境

设计模式-责任链模式

Owen Guo 2024-08-11 00:01:03
简介设计模式-责任链模式

问题背景

学校OA系统采购审批项目:需求时
1)采购员采购教学器材
2)如果金额小于等于5000,由教学主任审批
3)如果金额小于等于10000,由院长审批
4)如果金额小于等于30000,由副校长审批
5)如果金额小于等于40000,由校长审批

请设计完成采购审批项目

解决方案:传统方法

我们在程序里直接使用 if else 语句来判断这个审批交给谁来审批。

这样是最简单的,大家都知道该如何去写这样的代码。但是这样的代码和审批人是强耦合关系,非常不利于代码的扩展和维护。

责任链模式

基本介绍

1)职责链模式(Chain of Responsibility Pattern)又叫责任链模式,为请求创建一个接收者对象的链。这种模式对请求的发送者和接收者进行耦合。
2)职责链模式通常每个接受者都包含另一个对象接收者的引用。如果一个对象不能处理该请求,那么他会把相同的请求传给下一个接收者,依次类推。
3)这种类型的设计模式属于行为模式

UML类图

在这里插入图片描述
1)Handler抽象类定义了一个处理请求的接口,同时包含下一个Handler
2)ConcreteHandlerA、B是具体的处理者,处理它自己负责的请求,可以访问它的后继者(即处理下一个处理者),如果可以处理当前请求,则处理,否则就将该请求交给后续者去处理,从而形成一个职责链
3)Request类是全局的上下文,包含了很多属性,表示一个请求

职责链模式使多个对象都有机会处理请求,从而避免请求发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这个链条传递该请求,直到有一个对象处理它为止。

解决方案:责任链模式

UML类图

在这里插入图片描述

代码示例

public abstract class Approver {

    /**
     * 下一个节点
     */
    private Approver approver;

    public Approver getApprover() {
        return approver;
    }

    public void setApprover(Approver approver) {
        this.approver = approver;
    }

    /**
     * 处理请求
     *
     * @param purchaseRequest
     */
    public abstract void processRequest(PurchaseRequest purchaseRequest);
}
public class PurchaseRequest {
    /**
     * 金额
     */
    private Integer money;

    /**
     * 是否通过
     */
    private Boolean flag = Boolean.FALSE;

    /**
     * 审批通过人
     */
    private String name;

    public PurchaseRequest(Integer money) {
        this.money = money;
    }

    public Boolean getFlag() {
        return flag;
    }

    public void setFlag(Boolean flag) {
        this.flag = flag;
    }

    public Integer getMoney() {
        return money;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}
public class DepartmentApprover extends Approver{

    /**
     * 节点名称
     */
    private String name = "教学主任";

    /**
     * 支持审批的金额
     */
    private Integer money;

    /**
     * 构造器要传入下一个处理节点
     *
     */
    public DepartmentApprover(Integer money) {
        this.money = money;
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        // 代表审批通过了
        if (purchaseRequest.getFlag()) {
            return;
        }
        if (purchaseRequest.getMoney() <= money) {
            purchaseRequest.setFlag(Boolean.TRUE);
            purchaseRequest.setName(this.name);
        } else {
            if (super.getApprover() != null) {
                super.getApprover().processRequest(purchaseRequest);
            }
        }
    }
}
public class CollegeApprover extends Approver{

    /**
     * 节点名称
     */
    private String name = "院长";

    /**
     * 支持审批的金额
     */
    private Integer money;

    /**
     * 构造器要传入下一个处理节点
     *
     */
    public CollegeApprover(Integer money) {
        this.money = money;
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        // 代表审批通过了
        if (purchaseRequest.getFlag()) {
            return;
        }
        if (purchaseRequest.getMoney() <= money) {
            purchaseRequest.setFlag(Boolean.TRUE);
            purchaseRequest.setName(this.name);
        } else {
            if (super.getApprover() != null) {
                super.getApprover().processRequest(purchaseRequest);
            }
        }
    }
}
public class ViceSchoolMasterApprover extends Approver{

    /**
     * 节点名称
     */
    private String name = "副校长";

    /**
     * 支持审批的金额
     */
    private Integer money;

    /**
     * 构造器要传入下一个处理节点
     *
     */
    public ViceSchoolMasterApprover(Integer money) {
        this.money = money;
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        // 代表审批通过了
        if (purchaseRequest.getFlag()) {
            return;
        }
        if (purchaseRequest.getMoney() <= money) {
            purchaseRequest.setFlag(Boolean.TRUE);
            purchaseRequest.setName(this.name);
        } else {
            if (super.getApprover() != null) {
                super.getApprover().processRequest(purchaseRequest);
            }
        }
    }
}
public class SchoolMasterApprover extends Approver{

    /**
     * 节点名称
     */
    private String name = "校长";

    /**
     * 支持审批的金额
     */
    private Integer money;

    /**
     * 构造器要传入下一个处理节点
     *
     */
    public SchoolMasterApprover(Integer money) {
        this.money = money;
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        // 代表审批通过了
        if (purchaseRequest.getFlag()) {
            return;
        }
        if (purchaseRequest.getMoney() <= money) {
            purchaseRequest.setFlag(Boolean.TRUE);
            purchaseRequest.setName(this.name);
        } else {
            if (super.getApprover() != null) {
                super.getApprover().processRequest(purchaseRequest);
            }
        }
    }
}

测试用例

public class Client {
    public static void main(String[] args) {
        // 构建职责链节点
        DepartmentApprover departmentApprover = new DepartmentApprover(5000);
        CollegeApprover collegeApprover = new CollegeApprover(10000);
        ViceSchoolMasterApprover viceSchoolMasterApprover = new ViceSchoolMasterApprover(30000);
        SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover(40000);

        // 构建职责链
        departmentApprover.setApprover(collegeApprover);
        collegeApprover.setApprover(viceSchoolMasterApprover);
        viceSchoolMasterApprover.setApprover(schoolMasterApprover);


        // 创建请求
        PurchaseRequest purchaseRequest = new PurchaseRequest(8000);

        // 传入职责链进行审批
        departmentApprover.processRequest(purchaseRequest);

        // 查看结果
        System.out.println("是否审批通过:" + purchaseRequest.getFlag() + "审批人:" + purchaseRequest.getName());
    }
}

运行结果

在这里插入图片描述

注意事项和细节

1)将请求和处理分开,实现解耦,提高系统的灵活性
2)简化了对象,使对象不需要知道链的结构
3)性能会受到影响,特别是在链比较长的时候,因此需控制链中最大节点数量,一般通过在Handler中设置一个最大节点数量,在setNext()方法中判断是否已经超过阀值超过则不允许该链建立,避免出现超长链无意识地破坏系统性能
4)调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂
5)最佳应用场景:有多个对象可以处理同一个请求时,比如: 多级请求、请假/加薪等审批流程、Java Web中Tomcat对Encoding的处理、拦截器

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。