什么是责任链模式?
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
优缺点
优点:
1.降低耦合度。它将请求的发送者和接收者解耦。
2.单一职责原则,降低各环节处理的复杂度。
3.开闭原则,通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
缺点:
1.不能保证请求一定被接收和处理。
2.系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
3.要注意链内成员的顺序,顺序错了会导致意想不到的错误。
示例
责任链模式在 Java 中有着广泛的应用,例如Spring web中的拦截器,filter等,日志分等级记录。再例如很多工作中的审批流等。我们以日志处理场景为例,日志输出的阈值设置非常重要,一般情况下,在生产环境阈值会被设为 ERROR 或 WARN 来过滤出重要的日志信息,而在其他环境一般会设为 INFO。其逻辑为
Log Level | Output |
---|---|
ERROR | 只有 Error 等级日志会输出 |
WARN | Warn 和 Error 等级的日志会输出 |
INFO | Error, Warn, Error 全部输出 |
enum LogLevel {
INFO,
WARN,
ERROR
}
interface ILogHandler {
void log(LogLevel level, String msg);
}
class Logger implements ILogHandler {
private Logger nextLogger;
public Logger(Logger nextLogger) {
this.nextLogger = nextLogger;
}
@Override
public void log(LogLevel level, String msg) {
if (nextLogger != null) {
nextLogger.log(level, msg);
}
}
}
class ErrorLogHandler extends Logger {
public ErrorLogHandler(Logger nextLogger) {
super(nextLogger);
}
@Override
public void log(LogLevel level, String msg) {
if (LogLevel.ERROR == level) {
System.out.println(msg);
return;
} else {
super.log(level, msg);
}
}
}
class WarnLogHandler extends Logger {
public WarnLogHandler(Logger nextLogger) {
super(nextLogger);
}
@Override
public void log(LogLevel level, String msg) {
if (LogLevel.WARN == level) {
System.out.println(msg);
return;
} else {
super.log(level, msg);
}
}
}
class InfoLogHandler extends Logger {
public InfoLogHandler(Logger nextLogger) {
super(nextLogger);
}
@Override
public void log(LogLevel level, String msg) {
if (LogLevel.INFO == level) {
System.out.println(msg);
return;
} else {
super.log(level, msg);
}
}
}
class LoggerFactory {
public static Logger getLogger(LogLevel logThreshold) {
switch (logThreshold) {
case ERROR: return new ErrorLogHandler(null);
case WARN: return new WarnLogHandler(new ErrorLogHandler(null));
default: return new InfoLogHandler(new WarnLogHandler(new ErrorLogHandler(null)));
}
}
}
public static void main(String[] args) {
System.out.println("-----Info level threshold-----");
final Logger infoLogger = LoggerFactory.getLogger(LogLevel.INFO);
infoLogger.log(LogLevel.ERROR, "[ERROR] Out of memory!");
infoLogger.log(LogLevel.WARN, "[WARN] Invalid company name");
infoLogger.log(LogLevel.INFO, "[INFO] Hello World!");
System.out.println("-----Warn level threshold-----");
final Logger warnLogger = LoggerFactory.getLogger(LogLevel.WARN);
warnLogger.log(LogLevel.ERROR, "[ERROR] Out of memory!");
warnLogger.log(LogLevel.WARN, "[WARN] Invalid company name");
warnLogger.log(LogLevel.INFO, "[INFO] Hello World!");
System.out.println("-----Error level threshold-----");
final Logger errorLogger = LoggerFactory.getLogger(LogLevel.ERROR);
errorLogger.log(LogLevel.ERROR, "[ERROR] Out of memory!");
errorLogger.log(LogLevel.WARN, "[WARN] Invalid company name");
errorLogger.log(LogLevel.INFO, "[INFO] Hello World!");
}
Output
-----Info level threshold-----
[ERROR] Out of memory!
[WARN] Invalid company name
[INFO] Hello World!
-----Warn level threshold-----
[ERROR] Out of memory!
[WARN] Invalid company name
-----Error level threshold-----
[ERROR] Out of memory!