设计模式~责任链模式

73 阅读3分钟

1. 定义

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

3. UML类图

image.png

  • Handler:抽象处理者角色,声明一个请求处理的方法,并持有对下一个处理节点Handler对象的引用
  • ConcreteHandler:具体处理者,对请求进行处理,如果处理不了就将该请求转发给下一个处理者

4. 使用场景

  • 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态指定
  • 在请求处理者不明确的情况下向多个对象中的一个提交请求
  • 需要动态指定一组对象处理请求

5. 简单实现

  • 通常公司报销会有一个流程,譬如报销单的处理流程:报销500元内只需交给组长签字,500~1000元就需要组长统一转交给经理签字,而1000 ~ 5000就需要经理统一转交给总监签字,达到5000以上就需要总监统一转交给老板签字(虽然可能实际有出入,但当作一个模型又何尝不可),这可以当作一个比较典型的责任链模型
  • 创建一个抽象领导者
/**
 * 抽象领导类
 *
 * @author BTPJ  2022/11/21
 */
public abstract class Leader {
    /**
     * 下一个处理者,即更上级的领导
     */
    protected Leader nextHandler;

    /**
     * 处理报销请求
     *
     * @param money 报销金额
     */
    public final void handleRequest(int money) {
        if (money <= getApproveLimit()) {
            handle(money);
        } else {
            String handleLeader = "";
            String className = this.getClass().getSimpleName();
            switch (className) {
                case "GroupLeader":
                    handleLeader = "组长";
                    break;
                case "ManagerLeader":
                    handleLeader = "经理";
                    break;
                case "InspectorLeader":
                    handleLeader = "总监";
                    break;
                default:
                    handleLeader = "老板";
                    break;
            }
            System.out.println(handleLeader + "无法处理,需要转交给更上级处理");
            if (nextHandler != null) {
                nextHandler.handleRequest(money);
            }
        }
    }

    /**
     * 能处理的报销金额上限
     */
    protected abstract int getApproveLimit();

    /**
     * 报销实际处理
     *
     * @param money 报销金额
     */
    protected abstract void handle(int money);
}
  • 组长
/**
 * 组长
 *
 * @author BTPJ  2022/11/21
 */
public class GroupLeader extends Leader {
    @Override
    protected int getApproveLimit() {
        return 500;
    }

    @Override
    protected void handle(int money) {
        System.out.println("组长处理了" + money + "元报销单据");
    }
}
  • 经理
/**
 * 经理
 *
 * @author BTPJ  2022/11/21
 */
public class ManagerLeader extends Leader{
    @Override
    protected int getApproveLimit() {
        return 1000;
    }

    @Override
    protected void handle(int money) {
        System.out.println("经理处理了" + money + "元报销单据");
    }
}
  • 总监
/**
 * 总监
 *
 * @author BTPJ  2022/11/21
 */
public class InspectorLeader extends Leader{
    @Override
    protected int getApproveLimit() {
        return 5000;
    }

    @Override
    protected void handle(int money) {
        System.out.println("总监处理了" + money + "元报销单据");
    }
}
  • 老板
/**
 * 老板
 *
 * @author BTPJ  2022/11/21
 */
public class BossLeader extends Leader {
    @Override
    protected int getApproveLimit() {
        return Integer.MAX_VALUE;
    }

    @Override
    protected void handle(int money) {
        System.out.println("老板处理了" + money + "元报销单据");
    }
}
  • 客户端调用
/**
 * 客户端调用
 *
 * @author BTPJ  2022/11/21
 */
public class Client {

    public static void main(String[] args) {
        GroupLeader groupLeader = new GroupLeader();
        ManagerLeader managerLeader = new ManagerLeader();
        InspectorLeader inspectorLeader = new InspectorLeader();
        BossLeader bossLeader = new BossLeader();
        groupLeader.nextHandler = managerLeader;
        managerLeader.nextHandler = inspectorLeader;
        inspectorLeader.nextHandler = bossLeader;

        groupLeader.handleRequest(300);
        System.out.println("-----------------------------------");
        groupLeader.handleRequest(600);
        System.out.println("-----------------------------------");
        groupLeader.handleRequest(1200);
        System.out.println("-----------------------------------");
        groupLeader.handleRequest(6000);
    }
}

运行结果:
组长处理了300元报销单据
-----------------------------------
组长无法处理,需要转交给更上级处理
经理处理了600元报销单据
-----------------------------------
组长无法处理,需要转交给更上级处理
经理无法处理,需要转交给更上级处理
总监处理了1200元报销单据
-----------------------------------
组长无法处理,需要转交给更上级处理
经理无法处理,需要转交给更上级处理
总监无法处理,需要转交给更上级处理
老板处理了6000元报销单据

6. 源码中的使用场景

  • 用户点击事件的分发处理

7. 优缺点

  • 优点:
    • 可对请求者和处理者关系解耦,提高代码灵活性
  • 缺点:
    • 当责任链太长即处理者太多时,需要不断向下遍历,或多或少会影响性能