责任链模式是一种行为型设计模式。责任链模式的思想是:为请求创建了一个接收者对象的链,如果一个接收者对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
责任链模式涉及到2个角色:
- 抽象处理者(Handler):定义出一个处理请求的接口。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。
- 具体处理者(Concrete Handler):具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。
结构图:
具体代码实现:
// 抽象处理者
public abstract class Handler {
protected Handler successor; // 责任链上下一个处理者的引用
public Handler getSuccessor() {
return successor;
}
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void handle(); // 处理请求
}
// 具体处理者
public class HandlerA extends Handler {
@Override
public void handle() {
Handler s = getSuccessor();
if (s == null) {
// 如果没有下一个处理者,则自己处理
System.out.println("Handle!!");
} else {
// 如果有下一个处理者,则交由下一个处理者处理
System.out.println("Pass...");
s.handle();
}
}
}
// 客户
public class Client {
public void method() {
Handler h1 = new HandlerA();
Handler h2 = new HandlerA();
Handler h3 = new HandlerA();
Handler h4 = new HandlerA();
h1.setSuccessor(h2);
h2.setSuccessor(h3);
h3.setSuccessor(h4);
h1.handle();
}
}
// 测试
class ResponsibilityTest {
public static void main(String[] args) {
Client client = new Client();
client.method();
}
}
运行结果:
Pass…
Pass…
Pass…
Handle!!
可以看到,责任链模式并不创建出责任链。责任链的创建必须有系统的其它部分完成(不一定是客户)。
责任链模式降低了请求的发送端和接收端之间的耦合,使多个对象都有机会处理这个请求。一个链可以是一条线,一个环,一个树,也可以是现有树的一部分。链的拓扑结构可以是单连通的或多连通的,责任链模式并不指定责任链的拓扑结构,但是责任链模式要求在同一个时间里,命令只可以被传给一个下家(或被处理掉);而不可以传给多于一个下家。
责任链模式的缺点主要是性能问题。一方面,如果链很长,而真正处理请求的对象在链条末端,那么处理这个请求的时间就比较长;另一方面,链条中的每个节点都是一个对象,而有时候这当中很多对象在业务场景中可能根本用不上,这就造成了内存空间的浪费。
下面再提供一个例子,用责任链模式实现不同级别日志的输出。
// 日志级别枚举
public enum LogLevel {
INFO(1), WARNING(2), ERROR(3);
public int index;
LogLevel(int index) {
this.index = index;
}
}
// 抽象日志记录器
public abstract class Logger {
protected Logger nextLogger; // 责任链中下一个日志记录器的引用
protected LogLevel level; // 当前日志记录器的级别
public Logger getNextLogger() {
return nextLogger;
}
public void setNextLogger(Logger nextLogger) {
this.nextLogger = nextLogger;
}
// 写日志
public void log(LogLevel level, String msg) {
if (this.level.index < level.index) {
// 如果当前记录器级别过低,则交由下一个记录器处理
nextLogger.log(level, msg);
} else {
// 如果当前记录器级别高于要记录的级别,则直接处理
write(msg);
}
}
// 输出日志信息到控制台,根据日志级别不同显示的格式也不同
protected abstract void write(String msg);
}
// INFO级别的日志记录器
public class InfoLogger extends Logger {
public InfoLogger() {
this.level = LogLevel.INFO;
}
@Override
protected void write(String msg) {
System.out.printf("[INFO] %s\n", msg);
}
}
// WARNING级别的日志记录器
pulbic class WarningLogger extends Logger {
public WarningLogger() {
this.level = LogLevel.WARNING;
}
@Override
protected void write(String msg) {
System.out.printf("[WARNING] %s\n", msg);
}
}
// ERROR级别的日志记录器
public class ErrorLogger extends Logger {
public ErrorLogger() {
this.level = LogLevel.ERROR;
}
@Override
protected void write(String msg) {
System.out.printf("[ERROR] %s\n", msg);
}
}
// 客户
public class Client {
// 模拟一个写日志的方法
public void method(LogLevel level, String msg) {
Logger info = new InfoLogger();
Logger warn = new WarningLogger();
Logger error = new ErrorLogger();
// 构造责任链
info.setNextLogger(warn);
warn.setNextLogger(error);
// 向责任链中不同的节点发送请求,检验效果
info.log(level, msg);
warn.log(level, msg);
}
}
// 测试
class LoggerTest {
public static void main(String[] args) {
Client client = new Client();
client.method(LogLevel.ERROR, "An error occurred!!");
System.out.println("==========");
client.method(LogLevel.INFO, "There is an information");
}
}
运行结果:
[ERROR] An error occurred!!
[ERROR] An error occurred!!
==========
[INFO] There is an information.
[WARNING] There is an information.
结构图:
最后总结一下责任链模式的应用场景:
- 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
- 可动态指定一组对象处理请求。
在JAVA WEB中,责任链模式随处可见,典型的应用是各种的过滤器(Filter)。