1. 责任链模式概述
责任链模式为请求创建了一个接收者对象的链。这种模式基于请求的类型,对请求的发送者和接收者进行解耦。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
(1) 适用情况
在处理消息时需要过滤很多次的时候,比如filter的实现。
(2) 优点
可以将请求的发送者和请求的处理者进行解耦,发送者只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递。
(3) 缺点
对责任链的顺序有要求,可能会由于顺序错误导致非预期的问题。责任链上有些节点可能需要处理的情况较少,请求每次经过它会造成不必要的性能影响。
2. 责任链模式实例
使用过log4j的同学应该都知道,需要配置默认的日志打印级别。比该级别优先级更高的日志信息都会打印出来,而更低的则不会。
例如,在log4j2中的日志优先级从高到低为:OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL
如果当前设置的打印级别为info,则只会打印INFO、WARN、ERROR等等。
这里使用责任链模式,来模拟简单的日志打印过程。
(1) 创建Logger的抽象类
public abstract class Logger {
public static final int ERROR = 1;
public static final int DEBUG = 2;
public static final int INFO = 3;
// 责任链中的下一跳
private Logger nextLogger;
// 日志信息级别
protected int level;
public void setNextLogger(Logger nextLogger) {
this.nextLogger = nextLogger;
}
public void logMessage(int level, String message) {
// 优先级更高的日志都需要记录
if (level <= this.level) {
write(message);
}
// 如果责任链没有结束,则调用下一跳
if (nextLogger != null) {
nextLogger.logMessage(level, message);
}
}
protected abstract void write(String message);
}
(2) 实现不同级别的日志处理类
public class InfoLogger extends Logger {
public InfoLogger(int level) {
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Info::logger: " + message);
}
}
public class DebugLogger extends Logger {
public DebugLogger(int level) {
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Debug::logger: " + message);
}
}
public class ErrorLogger extends Logger {
public ErrorLogger(int level) {
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Error::logger: " + message);
}
}
(3) 打印不同级别的日志信息
public class ChainDemo {
public static void main(String[] args) {
Logger chainOfLoggers = getChainOfLoggers();
// 打印INFO日志
chainOfLoggers.logMessage(Logger.INFO, "INFO日志。");
// 打印DEBUG日志
chainOfLoggers.logMessage(Logger.DEBUG, "DEBUG日志。");
// 打印ERROR日志
chainOfLoggers.logMessage(Logger.ERROR, "ERROR日志。");
}
private static Logger getChainOfLoggers() {
Logger infoLogger = new InfoLogger(Logger.INFO);
Logger debugLogger = new DebugLogger(Logger.DEBUG);
Logger errorLogger = new ErrorLogger(Logger.ERROR);
// 按照优先级从高到低
errorLogger.setNextLogger(debugLogger);
debugLogger.setNextLogger(infoLogger);
return errorLogger;
}
}
运行结果:
3. 一些思考
从运行结果中可以看出,INFO日志只在InfoLogger中打印,DEBUG日志在DebugLogger和InfoLogger中都打印了,ERROR日志在三个日志处理类中都打印了,确实符合优先级的要求。
注意到getChainOfLoggers方法,只返回了errorLogger,即只返回了责任链的首部而已,确实将请求的发送者和处理者解耦了。