責任鏈模式不少框架都有用到,其中一個經典場景就是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.