【设计模式】责任链模式
一、前言
责任链模式很多框架都有用到,其中一个经典场景就是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.