责任链模式(Chain of Responsibility)

击鼓传花,层层审批,解决各种 if else 判断的复杂业务情况

责任链模式

概述

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

通常情况下每个接受者包含对另一个接收者的引用,意思就是这个接受者处理不了了,扔给下个人处理,或者这个人处理过了,给下一个人审批。

责任链就是一条链路,传入一个参数,按照事先排好的链路顺序,依次判断处理。

使用场景

有多个对象处理同一个请求的情况,具体哪个对象处理由运行时刻决定(可以理解为需要多次的 if 判断才能决定走哪个分支)

为什么要用责任链模式?直接用 if 判断不行吗?

简单情况下,确实没必要用责任链模式,但是如果 if 判断很多种情况,而且每个分支里处理的代码也有很多呢?必然会难以维护

这种情况责任链就是把每个分支抽出来一个文件,代码逻辑会清晰很多,而且先后处理顺序也是可以自定义的。

优缺点

  • 优点:
    1. 降低耦合度。它将请求的发送者和接收者解耦。
    2. 简化了对象。使得对象不需要知道链的结构。
    3. 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
    4. 增加新的请求处理类很方便。
  • 缺点:
    1. 不能保证请求一定被接收(可能所有对象都无法处理此请求)
    2. 写代码时不小心会造成循环调用
    3. 调试不方便,因为多个对象来回跳,没有 if 简单明了

类图

简单实现

场景

现在要实现一个日志记录器,根据传入的参数来判断是打印什么类型的日志

预先准备

传入的参数类型是日志类型的枚举:

public enum LoggerType {
    /** 普通日志 */
    INFO,
    /** 调试日志 */
    DEBUG,
    /** 错误日志 */
    ERROR
}

不用设计模式的写法

public class OriginalDemo {

    private void logMessage(LoggerType loggerType, String message) {
        if (loggerType == LoggerType.INFO) {
            System.out.println("INFO -- " + message);
        } else if (loggerType == LoggerType.DEBUG) {
            System.out.println("DEBUG -- " + message);
        } else if (loggerType == LoggerType.ERROR) {
            System.out.println("ERROR -- " + message);
        } else {
            System.out.println("无法识别日志类型:" + loggerType);
        }
    }

    public static void main(String[] args) {
        OriginalDemo originalDemo = new OriginalDemo();
        originalDemo.logMessage(LoggerType.INFO, "INFO 日志");
        originalDemo.logMessage(LoggerType.DEBUG, "DEBUG 日志");
        originalDemo.logMessage(LoggerType.ERROR, "ERROR 日志");
    }

}

运行结果:

INFO -- INFO 日志
DEBUG -- DEBUG 日志
ERROR -- ERROR 日志

使用责任链模式

整体思路梳理:就是把日志抽象出一个日志打印抽象类,然后三个分支依次继承,里面写自己的日志打印逻辑;日志抽象类中规划了 setNextLogger 的方法,设置下家,然后定义了 logMessage 方法,来供外部调用,然后 logMessage 中就是定义了判断日志类型的逻辑;

日志链顶层抽象类

public abstract class AbstractLogger {

    protected LoggerType loggerType;

    protected AbstractLogger nextLogger;

    public void setNextLogger(AbstractLogger nextLogger) {
        this.nextLogger = nextLogger;
    }

    public void logMessage(LoggerType loggerType, String message) {
        if (loggerType == this.loggerType) {
            outputMessage(message);
        }
        if (nextLogger != null) {
            nextLogger.logMessage(loggerType, message);
        }
    }

    /**
     * 实际输出日志逻辑
     * @param message 日志信息
     */
    abstract protected void outputMessage(String message);
}

三种类型的日志打印器

public class DebugLogger extends AbstractLogger {

    public DebugLogger() {
        this.loggerType = LoggerType.DEBUG;
    }

    @Override
    protected void outputMessage(String message) {
        System.out.println("DEBUG -- " + message);
    }
}
public class ErrorLogger extends AbstractLogger {

    public ErrorLogger() {
        this.loggerType = LoggerType.ERROR;
    }

    @Override
    protected void outputMessage(String message) {
        System.out.println("ERROR -- " + message);
    }
}
public class InfoLogger extends AbstractLogger {

    public InfoLogger() {
        this.loggerType = LoggerType.INFO;
    }

    @Override
    protected void outputMessage(String message) {
        System.out.println("INFO -- " + message);
    }
}

测试使用:

public class ChainPatternDemo {

    private static AbstractLogger getLoggerChain() {
        InfoLogger infoLogger = new InfoLogger();
        DebugLogger debugLogger = new DebugLogger();
        ErrorLogger errorLogger = new ErrorLogger();
        // info 下家是 debug 接手
        infoLogger.setNextLogger(debugLogger);
        // debug 下家 error 接手
        debugLogger.setNextLogger(errorLogger);
        // 责任链危险的地方,一个写不好就会循环调用,添加以下代码就会循环调用
        // errorLogger.setNextLogger(infoLogger);
        return infoLogger;
    }


    public static void main(String[] args) {
        AbstractLogger loggerChain = getLoggerChain();

        loggerChain.logMessage(LoggerType.INFO, "INFO 日志测试");
        loggerChain.logMessage(LoggerType.DEBUG, "DEBUG 日志测试");
        loggerChain.logMessage(LoggerType.ERROR, "ERROR 日志测试");
    }
}

输出结果:

INFO -- INFO 日志测试
DEBUG -- DEBUG 日志测试
ERROR -- ERROR 日志测试

责任链模式(Chain of Responsibility)
https://www.powercheng.fun/articles/6d929472/
作者
powercheng
发布于
2022年3月15日
许可协议