设计模式-责任链模式

102 阅读3分钟

一、责任链模式介绍

责任链模式(Chain of Responsibility Pattern)也叫职责链模式。:为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。

责任链模式的本质是解耦请求与处理,让请求在处理链中能进行传递与被处理;理解责任链模式应当理解其模式,而不是其具体实现。责任链模式的独到之处是将其节点处理者组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动起来。

职责链模式主要包含以下角色

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

此处我们有一个诉求

  • 员工作为请求者提交请假申请,根据不同请假天数交给不同的责任人进行审批。
  • 请假3天以内交由直接上级审批,3天以上7天以内交由主管审批,而7天以上10天以内则交由部长进行审批。
  • 此处我们使用责任链模式实现该诉求。

二、责任链模式使用

2.1 示例关系:

2.2 代码实现:

/* *
 * 1. 领导抽象类(Handler)。
 */

abstract class Leader {

    protected Leader nextLeader;

    public Leader getNextLeader() {
        return nextLeader;
    }

    public void setNextLeader(Leader nextLeader) {
        this.nextLeader = nextLeader;
    }


    /* *
     * 处理请求的请假天数。
     */

    public abstract void handleRequest(int leaveDays);
}



/* *
 * 2. 直接上级类继承领导抽象类(Concrete Handler)。
 */

class Supervisor extends Leader {

    @Override
    public void handleRequest(int leaveDays) {
        if (0 < leaveDays && leaveDays <= 3) {
            System.out.println(" 直接上级允许通过,请假" + leaveDays + "天。");
        } else {
            // 若不满足批准条件,则交给下一Handler进行处理。
            if (null != getNextLeader()) {
                getNextLeader().handleRequest(leaveDays);
            } else {
                System.out.println(" 请假天数不在审批范围内,请重新调整后进行提交! ");
            }
        }
    }

}



/* *
 * 3. 主管类继承领导抽象类(Concrete Handler)。
 */

class Manager extends Leader {

    @Override
    public void handleRequest(int leaveDays) {
        if (3 < leaveDays && leaveDays <= 7) {
            System.out.println(" 主管允许通过,请假" + leaveDays + "天。");
        } else {
            if (null != getNextLeader()) {
                getNextLeader().handleRequest(leaveDays);
            } else {
                System.out.println(" 请假天数不在审批范围内,请重新调整后进行提交! ");
            }
        }
    }

}



/* *
 * 4. 部长类继承领导抽象类(Concrete Handler)。
 */

class Secretary extends Leader {

    @Override
    public void handleRequest(int leaveDays) {
        if (7 < leaveDays && leaveDays <= 10) {
            System.out.println(" 部长允许通过,请假" + leaveDays + "天。");
        } else {
            if (null != getNextLeader()) {
                getNextLeader().handleRequest(leaveDays);
            } else {
                System.out.println(" 请假天数不在审批范围内,请重新调整后进行提交! ");
            }
        }
    }

}



/* *
 * 5. 客户端调用。
 */

public class Client {

    public static void main(String[] args) {
        // 创建Handler。
        Leader leader1 = new Supervisor();
        Leader leader2 = new Manager();
        Leader leader3 = new Secretary();

        // 添加责任链。
        leader1.setNextLeader(leader2);
        leader2.setNextLeader(leader3);

        leader1.handleRequest(3);
        //  直接上级允许通过,请假3天。

        leader1.handleRequest(7);
        // 主管允许通过,请假7天。

        leader1.handleRequest(10);
        // 部长允许通过,请假10天。

        leader1.handleRequest(15);
        // 请假天数不在审批范围内,请重新调整后进行提交!
    }

}

三、责任链模式总结

优点

  • 请求和处理分开,实现解耦,提高系统的灵活性。
  • 简化了对象的调用,使对象不需要知道链的结构。

缺点

  • 性能会受到影响,特别是在链比较长的时候,因此需要控制链中最大节点数量(一般做法是在Handler中设置一个最大节点数量,在setNext()方法中判断是否已经超过阈值,超过则不允许该链创建,避免出现超长链无意识地破坏系统性能)。
  • 采用了类似递归的方式,逻辑可能比较复杂,从而带来调试的不便

应用场景

  • 多个对象可以处理一个请求,但具体由哪个对象处理该请求在运行时自动确定。
  • 多级请求、如请假/加薪等审批流程。
  • Java WebTomcatEncoding的处理、拦截器。
  • SpringMVCHandlerExecutionChain类使用到了该模式。

四、结束语

“-------怕什么真理无穷,进一寸有一寸的欢喜。”

微信公众号搜索:饺子泡牛奶