责任链模式(Chain of Responsibility)
责任链模式(Chain of Responsibility)是一种行为型设计模式,旨在通过将请求沿着一系列处理者传递,形成一条处理链,直到请求被处理链上特定的结点处理为止。它允许多个对象有机会处理请求,而不需要明确指定哪个对象将处理该请求。每个处理者包含对下一个处理者的引用,如果当前处理者无法处理请求,它会将请求传递给下一个处理者。这样可以将请求的处理职责链式地分配给多个处理者,而不需要将它们紧密耦合。
组成部分
-
抽象处理者(Handler):定义一个处理请求的接口,并且持有一个指向下一个处理者的引用。如果当前处理者无法处理请求,就将其传递给下一个处理者。
-
具体处理者(ConcreteHandler):实现抽象处理者的接口,处理请求。如果无法处理,则传递给下一个处理者。
-
客户端(Client):发起请求,并将请求发送到责任链的起始点。
案例实现
假设我们需要处理不同等级的日志信息,并根据不同的日志等级,将日志信息写入不同的日志文件。日志等级包括info、debug、error和warning 日志级别。使用者只需指定日志级别,即可在责任链对象中自动处理对应的日志信息。
注:为了代码的实现简单,这里不编写具体的写入文件IO流操作,只是控制台输出。
设计思路
-
handleLog
方法:每个LogHandler
只关注自己的日志级别,并在处理完成后调用nextHandler
的handleLog
方法; -
责任链的链式处理:
LoggerChain
类负责维护日志处理器的顺序,并且通过一个nextHandler
参数将责任传递给下一个处理器,实现责任的传递; -
灵活扩展:不需要每个处理器显式管理
nextHandler
,在理想情况下只需要维护日志枚举类即可。
案例类图
1. 定义LogHandler接口
在接口中,handleLog
方法接收一个 nextHandler
参数,决定是否将日志传递给下一个处理器。
public interface LogHandler {
void handleLog(LoggerEnum logLevel, String message, LogHandler nextHandler);
}
2. 具体日志处理器实现
每个日志处理器只关心自己负责的日志等级,如果当前处理器能处理,则输出日志,并将控制权交给下一个处理器。
public class InfoLogHandler implements LogHandler {
@Override
public void handleLog(LoggerEnum logLevel, String message, LogHandler nextHandler) {
if (logLevel.shouldLog(LoggerEnum.INFO)) {
System.out.println(this.getClass().getSimpleName() + ">> INFO: " + message);
}
// 如果存在下一个处理器
if (nextHandler != null) {
nextHandler.handleLog(logLevel, message, nextHandler);
}
}
}
class DebugLogHandler implements LogHandler {
@Override
public void handleLog(LoggerEnum logLevel, String message, LogHandler nextHandler) {
if (logLevel.shouldLog(LoggerEnum.DEBUG)) {
System.out.println(this.getClass().getSimpleName() + ">> DEBUG: " + message);
}
// 如果存在下一个处理器
if (nextHandler != null) {
nextHandler.handleLog(logLevel, message, nextHandler);
}
}
}
class ErrorLogHandler implements LogHandler {
@Override
public void handleLog(LoggerEnum logLevel, String message, LogHandler nextHandler) {
if (logLevel.shouldLog(LoggerEnum.ERROR)) {
System.out.println(this.getClass().getSimpleName() + ">> ERROR: " + message);
}
// 如果存在下一个处理器
if (nextHandler != null) {
nextHandler.handleLog(logLevel, message, nextHandler);
}
}
}
class WarningLogHandler implements LogHandler {
@Override
public void handleLog(LoggerEnum logLevel, String message, LogHandler nextHandler) {
if (logLevel.shouldLog(LoggerEnum.WARNING)) {
System.out.println(this.getClass().getSimpleName() + ">> WARNING: " + message);
}
// 如果存在下一个处理器
if (nextHandler != null) {
nextHandler.handleLog(logLevel, message, nextHandler);
}
}
}
3. 创建处理器链
public class LoggerChain implements LogHandler{
private int currentPosition = 0;
private List<LogHandler> handlers = new ArrayList<>();
// 初始化日志责任链时可以结合创建型设计模式来动态实现,符合开闭原则
public LoggerChain() {
// 自动创建并排序处理器,按优先级从低到高
handlers.add(new InfoLogHandler());
handlers.add(new DebugLogHandler());
handlers.add(new ErrorLogHandler());
handlers.add(new WarningLogHandler());
}
// 处理日志
public void log(LoggerEnum logLevel, String message) {
this.handleLog(logLevel,message,null);
}
@Override
public void handleLog(LoggerEnum logLevel, String message, LogHandler nextHandler) {
if (currentPosition == handlers.size()) {
// 退出责任链
currentPosition = 0;
}else{
LogHandler firstHandler = handlers.get(currentPosition++);
firstHandler.handleLog(logLevel, message, this);
}
}
}
4. 日志等级枚举
LoggerEnum
枚举定义了不同的日志等级
public enum LoggerEnum {
INFO(1), // 信息日志
DEBUG(2), // 调试日志
ERROR(3), // 错误日志
WARNING(4); // 警告日志
private final int priority;
LoggerEnum(int priority) {
this.priority = priority;
}
public int getPriority() {
return priority;
}
// 判断当前等级是否符合输出要求:比如Debug级别的日志可以输出debug和info的日志
public boolean shouldLog(LoggerEnum currentLogLevel) {
return this.priority >= currentLogLevel.getPriority();
}
}
5. 测试类
public class LoggerTest {
public static void main(String[] args) {
LoggerChain loggerChain = new LoggerChain();
// 模拟不同日志级别的请求
System.out.println("日志级别: INFO");
loggerChain.log(LoggerEnum.INFO, "这是 info 信息.");
System.out.println("\n日志级别: DEBUG");
loggerChain.log(LoggerEnum.DEBUG, "这是 debug 信息.");
System.out.println("\n日志级别: ERROR");
loggerChain.log(LoggerEnum.ERROR, "这是 error 信息.");
System.out.println("\n日志级别: WARNING");
loggerChain.log(LoggerEnum.WARNING, "这是 warning 信息.");
}
}
执行结果
在这个案例中,初始化日志责任链时可以结合创建型设计模式来动态实现,才符合开闭原则,新增或删除日志级别时只需要维护枚举类即可。将控制台输出改为IO流写入文件,即可实现不同日志级别的信息写入到不同的日志文件。
优缺点和应用场景
优点
-
降低耦合度:客户端不需要知道哪个具体的对象会处理请求,处理请求的对象可以动态变化;
-
扩展性强:新的处理器可以很容易地被添加到责任链中,且不需要修改现有的代码;
-
职责分离:每个处理者只关注自己能处理的逻辑,职责清晰。
缺点
-
链过长时可能造成性能问题:请求可能在链中经过多个处理者,这可能导致性能上的损耗,尤其是责任链较长时;
-
调试复杂性:由于请求被多个处理者处理,调试时可能较难追踪请求的流转路径;
-
请求可能永远无法得到处理:如果责任链中的所有处理器都没有处理该请求,则请求会被忽略或终止。这种情况可能会导致某些请求得不到预期的处理结果,需要在设计时注意链的完整性和错误处理机制。
应用场景
1、日志记录:责任链模式可以用于日志记录的处理。不同的日志级别(例如,INFO、DEBUG、ERROR)可以通过责任链模式传递,依次被不同的日志处理器(如控制台日志、文件日志、网络日志等)处理。
2、权限校验:在复杂的权限校验中,不同的权限校验可以作为责任链的一部分,依次处理。每个处理器检查不同的权限要求,直到满足条件或结束。
例子:在SpringSecurity中,访问控制或权限校验可以通过过滤链
模式来实现。例如,检查用户是否拥有访问某个页面的权限,可以通过多个权限处理器(如角色权限、用户权限、IP 白名单等)进行逐层处理。
3、请求过滤:Servlet 的过滤器链(Filter Chain),每个过滤器负责请求的某个方面(例如,身份验证、权限检查、日志记录等)。请求被传递到链中的下一个过滤器,直到最终响应。
4、表单验证:表单验证可以通过责任链模式进行处理,每个验证器可以处理不同的验证规则,直到表单满足所有验证条件。
例子:在表单提交时,可以有多个验证器(如空值检查、格式验证、长度验证、范围验证等),每个验证器都负责处理不同的验证逻辑。
5、数据处理管道:在数据处理流程中,责任链模式适合于处理多个步骤的数据流。每个步骤可以视为一个处理器,负责对数据进行某种操作,数据会被传递到下一个步骤。
例子:数据清洗和转换流程中,每个数据清洗步骤(如去除空值、格式化、转换编码等)可以作为责任链的一部分,按顺序处理数据。
责任链模式的应用
Spring Security的过滤链(Filter Chain)是责任链模式的一种典型实现。它是一个按顺序执行的过滤器集合,负责拦截和处理HTTP请求,以实现认证、授权、安全控制等功能,并且支持自定义过滤器插入到Spring Security的过滤链中,从而实现自定义的安全处理逻辑,使得Spring Security变得更加灵活。
总结
责任链设计模式是一种行为设计模式,其核心在于将多个处理对象连接成一条链,允许请求沿链传递,直到有一个处理者能够处理该请求,从而实现请求的解耦和动态的处理顺序管理,并且处理者易于扩展,使得程序更加灵活。
标签:LoggerEnum,请求,掌握,--,处理,nextHandler,日志,设计模式,message From: https://blog.csdn.net/sdgfafg_25/article/details/145186228文章转载自:渊渟岳