【设计模式】责任链模式
一、前言
责任链模式很多框架都有用到,其中一个经典场景就是Tomcat对HTTP请求的处理。
Tomcat处理HTTP请求时就会处理请求头和请求体两部分,当然,Tomcat的真正实现会将HTTP请求切分成更细的部分进行处理。如果请求各部分的逻辑都在一个类中实现,这个类会非常臃肿。如果请求通过增加新字段完成升级,则接受者需要添加处理新字段的处理逻辑,这就需要修改该类的代码,不符合“开放-封闭”原则。
责任链模式就可以很好地处理上述问题,将上述完整的、臃肿的接受者的实现逻辑拆分到多个只包含部分逻辑的、功能单一的Handler处理类中,开发人员可以根据业务需求将多个Handler对象组合成一条责任链,实现请求的处理。在一条责任链中,每个Handler对象都包括对下一个Handler对象的引用,一个Handler对象处理完请求消息(或不能处理该请求)时,会把请求传给下一个Handler对象继续处理,以此类推,直至整条责任链结束。
责任链模式的类图如下:

优点:
1.弱化了发出请求的人和处理请求的人之间的关系
2.可以动态的改变责任链,删除或者添加或者改变顺序。
3.让各个处理者专注于实现自己的职责
缺点
1.如果构造的责任链变成了环形结构,进行代码调试和定位问题比较困难
2.推卸责任也可能导致处理延迟
二、初始版实现
需求是给定一个日志级别,不高于这个日志级别的日志记录器都会打印自己的日志信息。
第一步:创建抽象日志处理器
AbstractLogger
public abstract class AbstractLogger { public static int INFO = 1; public static int DEBUG = 2; public static int ERROR = 3; protected int level; // 责任链中的下一个元素 protected AbstractLogger nextLogger; public void setNextLogger(AbstractLogger nextLogger) { this.nextLogger = nextLogger; } public void logMessage(int level, String message) { if (this.level <= level) { write(message); } if (nextLogger != null) { nextLogger.logMessage(level, message); } } abstract protected void write(String message); }
第二步:具体日志处理器
ConsoleLogger
public class ConsoleLogger extends AbstractLogger { public ConsoleLogger(int level){ this.level = level; } @Override protected void write(String message) { System.out.println("Standard Console::Logger: " + message); } }
ErrorLogger
public class ErrorLogger extends AbstractLogger { public ErrorLogger(int level){ this.level = level; } @Override protected void write(String message) { System.out.println("Error Console::Logger: " + message); } }
FileLogger
public class FileLogger extends AbstractLogger { public FileLogger(int level) { this.level = level; } @Override protected void write(String message) { System.out.println("File::Logger: " + message); } }
ChainPatternDemo
public class ChainPatternDemo { public static void main(String[] args) { AbstractLogger loggerChain = getChainOfLoggers(); loggerChain.logMessage(AbstractLogger.INFO, "This is an information."); loggerChain.logMessage(AbstractLogger.DEBUG, "This is an debug level information."); loggerChain.logMessage(AbstractLogger.ERROR, "This is an error information."); } private static AbstractLogger getChainOfLoggers(){ ErrorLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR); FileLogger fileLogger = new FileLogger(AbstractLogger.DEBUG); ConsoleLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO); errorLogger.setNextLogger(fileLogger); fileLogger.setNextLogger(consoleLogger); return errorLogger; } }
运行Main方法,测试结果如图。

三、升级版实现
上面的方式实现了功能,但是不够优雅,还需要手动调用setXX方法来设置引用,于是有了下面升级版的实现。
类图如下:

FilterChain
public class FilterChain extends AbstractLoggerFilter { private int pos; private List<AbstractLoggerFilter> loggerFilterList; public void addFilter(AbstractLoggerFilter loggerFilter) { if (loggerFilterList == null) { loggerFilterList = new ArrayList<>(); } loggerFilterList.add(loggerFilter); } @Override void doFilter(int level, FilterChain filterChain) { if (pos == loggerFilterList.size()) { return; } filterChain.loggerFilterList.get(pos++).doFilter(level, filterChain); } }
这个过滤器链有两个属性,pos用于表示当前过滤器在过滤器集合中的角标,loggerFilterList是过滤器的集合。
doFilter() 方法先判断是否全部处理完了,如果不是就交给下个处理器去处理,递归调用。
AbstractLoggerFilter
public abstract class AbstractLoggerFilter { abstract void doFilter(int level,FilterChain filterChain); }
ConsoleLoggerFilter
public class ConsoleLoggerFilter extends AbstractLoggerFilter { private LoggerInfo loggerInfo; public ConsoleLoggerFilter(LoggerInfo loggerInfo){ this.loggerInfo = loggerInfo; } @Override void doFilter(int level, FilterChain filterChain) { if (loggerInfo.getLevel() <= level){ System.out.println("Standard Console::Logger: " + loggerInfo.getMessage()); } filterChain.doFilter(level,filterChain); } }
ErrorLoggerFilter
public class ErrorLoggerFilter extends AbstractLoggerFilter { private LoggerInfo loggerInfo; public ErrorLoggerFilter(LoggerInfo loggerInfo){ this.loggerInfo = loggerInfo; } @Override void doFilter(int level, FilterChain filterChain) { if (loggerInfo.getLevel() <= level){ System.out.println("Error Console::Logger: " + loggerInfo.getMessage()); } filterChain.doFilter(level,filterChain); } }
FileLoggerFilter
public class FileLoggerFilter extends AbstractLoggerFilter { private LoggerInfo loggerInfo; public FileLoggerFilter(LoggerInfo loggerInfo){ this.loggerInfo = loggerInfo; } @Override void doFilter(int level, FilterChain filterChain) { if (loggerInfo.getLevel() <= level){ System.out.println("File::Logger: " + loggerInfo.getMessage()); } filterChain.doFilter(level,filterChain); } }
实体类LoggerInfo
public class LoggerInfo { private int level; private String message; public LoggerInfo(int level, String message) { this.level = level; this.message = message; } //省略get/set方法 }
客户端LoggerFilterDemo
public class LoggerFilterDemo { public static int INFO = 1; public static int DEBUG = 2; public static int ERROR = 3; public static void main(String[] args) { ConsoleLoggerFilter consoleLoggerFilter = new ConsoleLoggerFilter( new LoggerInfo(INFO, "This is an information.")); ErrorLoggerFilter errorLoggerFilter = new ErrorLoggerFilter( new LoggerInfo(ERROR, "This is an error information.")); FileLoggerFilter fileLoggerFilter = new FileLoggerFilter( new LoggerInfo(DEBUG, "This is an debug level information.")); FilterChain filterChain = new FilterChain(); filterChain.addFilter(consoleLoggerFilter); filterChain.addFilter(errorLoggerFilter); filterChain.addFilter(fileLoggerFilter); filterChain.doFilter(ERROR, filterChain); } }
如果以后还需要添加新类型的Logger,只需要new出来添加到FilterChain中就可以了。
运行测试类,可以看到所有类型的Logger都打印了日志。
Standard Console::Logger: This is an information. Error Console::Logger: This is an error information. File::Logger: This is an debug level information.
本文作者:烟味i
本文链接:https://www.cnblogs.com/2YSP/p/11482845.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步