责任链模式不少框架都有用到,其中一个经典场景就是Tomcat对HTTP请求的处理。
Tomcat处理HTTP请求时就会处理请求头和请求体两部分,固然,Tomcat的真正实现会将HTTP请求切分红更细的部分进行处理。若是请求各部分的逻辑都在一个类中实现,这个类会很是臃肿。若是请求经过增长新字段完成升级,则接受者须要添加处理新字段的处理逻辑,这就须要修改该类的代码,不符合“开放-封闭”原则。
责任链模式就能够很好地处理上述问题,将上述完整的、臃肿的接受者的实现逻辑拆分到多个只包含部分逻辑的、功能单一的Handler处理类中,开发人员能够根据业务需求将多个Handler对象组合成一条责任链,实现请求的处理。在一条责任链中,每一个Handler对象都包括对下一个Handler对象的引用,一个Handler对象处理完请求消息(或不能处理该请求)时,会把请求传给下一个Handler对象继续处理,以此类推,直至整条责任链结束。
责任链模式的类图以下:html
需求是给定一个日志级别,不高于这个日志级别的日志记录器都会打印本身的日志信息。
第一步:建立抽象日志处理器
AbstractLoggerjava
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);
}
第二步:具体日志处理器
ConsoleLoggergit
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);
}
}
ErrorLoggergithub
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);
}
}
FileLoggerbash
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方法,测试结果如图。ide
上面的方式实现了功能,可是不够优雅,还须要手动调用setXX方法来设置引用,因而有了下面升级版的实现。
类图以下:测试
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() 方法先判断是否所有处理完了,若是不是就交给下个处理器去处理,递归调用。this
AbstractLoggerFilterspa
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.