责任链模式(Chain of Responsibility)
击鼓传花,层层审批,解决各种 if else 判断的复杂业务情况
责任链模式
概述
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
通常情况下每个接受者包含对另一个接收者的引用,意思就是这个接受者处理不了了,扔给下个人处理,或者这个人处理过了,给下一个人审批。
责任链就是一条链路,传入一个参数,按照事先排好的链路顺序,依次判断处理。
使用场景
有多个对象处理同一个请求的情况,具体哪个对象处理由运行时刻决定(可以理解为需要多次的 if 判断才能决定走哪个分支)
为什么要用责任链模式?直接用 if 判断不行吗?
简单情况下,确实没必要用责任链模式,但是如果 if 判断很多种情况,而且每个分支里处理的代码也有很多呢?必然会难以维护
这种情况责任链就是把每个分支抽出来一个文件,代码逻辑会清晰很多,而且先后处理顺序也是可以自定义的。
优缺点
- 优点:
- 降低耦合度。它将请求的发送者和接收者解耦。
- 简化了对象。使得对象不需要知道链的结构。
- 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
- 增加新的请求处理类很方便。
- 缺点:
- 不能保证请求一定被接收(可能所有对象都无法处理此请求)
- 写代码时不小心会造成循环调用
- 调试不方便,因为多个对象来回跳,没有 if 简单明了
类图
![image-20220315094121102](/articles/6d929472/e36Ba55B50image-20220315094121102.png)
简单实现
场景
现在要实现一个日志记录器,根据传入的参数来判断是打印什么类型的日志
预先准备
传入的参数类型是日志类型的枚举:
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 中就是定义了判断日志类型的逻辑;
![image-20220315094909661](/articles/6d929472/ce8FF70CcAimage-20220315094909661.png)
日志链顶层抽象类
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/