责任链模式
1. 概念
责任链模式是一种处理请求的模式,它让多个对象(处理器)都有机会处理该请求,直到其中某个处理成功为止。责任链模式把多个对象串成链,然后让请求在链上传递:
┌─────────┐
│ Request │
└─────────┘
│
┌ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ┐
▼
│ ┌─────────────┐ │
│ ProcessorA │
│ └─────────────┘ │
│
│ ▼ │
┌─────────────┐
│ │ ProcessorB │ │
└─────────────┘
│ │ │
▼
│ ┌─────────────┐ │
│ ProcessorC │
│ └─────────────┘ │
│
└ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ┘
│
▼
2. 示例
我们创建抽象类 AbstractLogger
,带有详细的日志记录级别。然后我们创建三种类型的记录器,都扩展了 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); }
创建扩展了该记录器类的实体类
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); } }
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); } }
public class FileLogger extends AbstractLogger { public FileLogger(int level){ this.level = level; } @Override protected void write(String message) { System.out.println("File::Logger: " + message); } }
创建不同类型的记录器,赋予它们不同的错误级别,并在每个记录器中设置下一个记录器,每个记录器中的下一个记录器代表的是链的一部分。
public class ChainPatternDemo { private static AbstractLogger getChainOfLoggers(){ AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR); AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG); AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO); errorLogger.setNextLogger(fileLogger); fileLogger.setNextLogger(consoleLogger); return errorLogger; } public static void main(String[] args) { AbstractLogger loggerChain = getChainOfLoggers(); loggerChain.logMessage(AbstractLogger.INFO, "This is an information."); loggerChain.logMessage(AbstractLogger.DEBUG, "This is a debug level information."); loggerChain.logMessage(AbstractLogger.ERROR, "This is an error information."); } }
执行程序,输出结果: Standard Console::Logger: This is an information. File::Logger: This is a debug level information. Standard Console::Logger: This is a debug level information. Error Console::Logger: This is an error information. File::Logger: This is an error information. Standard Console::Logger: This is an error information.
变种
责任链模式有很多变种。有些责任链的实现方式是通过某个Handler
手动调用下一个Handler
来传递Request
,例如:
public class AHandler implements Handler {
private Handler next;
public void process(Request request) {
if (!canProcess(request)) {
// 手动交给下一个Handler处理:
next.process(request);
} else {
...
}
}
}
变种:拦截器/过滤器
还有一些责任链模式,每个Handler
都有机会处理Request
,通常这种责任链被称为拦截器(Interceptor)或者过滤器(Filter),它的目的不是找到某个Handler
处理掉Request
,而是每个Handler
都做一些工作,比如:
- 记录日志;
- 检查权限;
- 准备相关资源;
- ...
例如,JavaEE的Servlet规范定义的Filter
就是一种责任链模式,它不但允许每个Filter
都有机会处理请求,还允许每个Filter
决定是否将请求“放行”给下一个Filter
:
public class AuditFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
log(req);
if (check(req)) {
// 放行:
chain.doFilter(req, resp);
} else {
// 拒绝:
sendError(resp);
}
}
}
这种模式不但允许一个Filter
自行决定处理ServletRequest
和ServletResponse
,还可以“伪造”ServletRequest
和ServletResponse
以便让下一个Filter
处理,能实现非常复杂的功能。
Tomcat中的责任链
在Tomcat中容易发现的设计模式即是责任链模式,这个设计模式也是在Tomcat中Container
设计的基础,整个容器就是通过一个链连接在一起的,这个链一直将请求正确地传递给最终处理请求的那个Servlet
:
