文章目录
责任链模式(Chain of Responsibility Pattern)
责任链模式也叫职责链模式(Chain of Responsibility Pattern)属于行为型模式。
什么是责任链模式?
避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
UML
角色
- **抽象处理者(Handler)**角色:定义一个抽象的请求处理接口,其中包含下一个处理接口。
- **具体处理者(Concrete Handler)**角色:实现抽象处理者的处理方法,先判断能否处理本次请求,再根据实际情况进行处理或者传递到下一个具体处理者处理。
- **客户类(Client)**角色:创建处理链并向链头的具体处理者对象提交请求。
应用
使用模板
public class ChainOfResponsibilityPattern {
public static void main(String[] args) {
//创建并设置责任链
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
Handler handlerC = new ConcreteHandlerC();
handlerA.setNext(handlerB);
handlerB.setNext(handlerC);
//责任链处理请求
handlerA.handleRequest("A");
handlerA.handleRequest("C");
handlerA.handleRequest("D");
}
}
//抽象处理者
abstract class Handler {
//存储后续处理者
private Handler next;
//设置后续处理者
protected void setNext(Handler next) { this.next = next; }
//获取后续处理者
public Handler getNext() { return next; }
//处理请求
public abstract void handleRequest(String request);
//未被处理的通用方法,该处抽象到父类只是为了代码的简洁
protected void finished(String request){
if (getNext() != null) {
getNext().handleRequest(request);
} else { System.out.println("职责链执行结束,请求未被处理!"); }
}
}
//具体处理者角色A
class ConcreteHandlerA extends Handler {
//重写处理请求的方法
@Override
public void handleRequest(String request) {
//判断是否需要该处理者处理
if (request.equals("A")) {
System.out.println("该请求已被处理——具体处理者A");
} else { finished(request); }
}
}
//同上
class ConcreteHandlerB extends Handler {
public void handleRequest(String request) {
if (request.equals("B")) {
System.out.println("该请求已被处理——具体处理者B");
} else { finished(request); }
}
}
//同上
class ConcreteHandlerC extends Handler {
public void handleRequest(String request) {
if (request.equals("C")) {
System.out.println("该请求已被处理——具体处理者C");
} else { finished(request); }
}
}
为什么要使用责任链模式?
优点
- 解耦。它将请求的发送者和接收者解耦,请求发出者不需要知道链的结构,弱化了请求发出者和请求处理者之间的关系。
- 灵活。客户端可以动态的组合责任链,通过增减链内的成员或者调动它们的次序。
- 专职。让各个处理者专注于实现自己的职责,无需过多的关注其他问题。
缺点
- 漏处理请求。不能保证请求一定被接收。
- 影响性能。如果责任链太长 , 或责任链中请求的处理时间过长 , 可能会影响性能 。
- 复杂。责任链可能过多 ,而且引用不当会死循环。
怎样使用责任链模式?
职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。
适用场景:
- 多个对象可以处理同一请求,但不确定具体由哪个对象处理,在运行时需要动态决定。
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
使用举例:
- 系统的登录流程,验证码、账号、密码等,作为一个责任链每个处理者负责各自的部分。
javax.servlet.Filter#doFilter()
java.util.logging.Logger#log(LogRecord record)
举例分析
java.util.logging.Logger#log(LogRecord record)
角色对应关系
该类对应了抽象与具体处理者。
- 其中
Logger parent
即存储的后续处理者
。 void log(LogRecord record)
处理请求。
package java.util.logging;
...
public class Logger {
...
//该类的上一级日志对象
private volatile Logger parent; // our nearest parent.
...
public void log(LogRecord record) {
...
//当前的日志(不确定上一级日志对象)是否存在,并且进入循环。
Logger logger = this;
while (logger != null) {
//细节处理
...
//此处判断是否需要使用其上级日志处理
final boolean useParentHdls = isSystemLogger
? logger.useParentHandlers
: logger.getUseParentHandlers();
//如果无需使用上级处理则跳出循环
if (!useParentHdls) {
break;
}
//该处为切换到上级处理对象继续进行执行循环体,直到需要的顶级日志处理,通过上一步结束该循环体。
logger = isSystemLogger ? logger.parent : logger.getParent();
}
}
...
}
在上述代码中,合并了抽象处理者
与具体处理者
,但是依旧使用的责任链的逻辑。后续的使用仅仅需要创建不同级别的日志对象,再将不同的按照顺序放入下一个级别的属性parent
中。
拓展
职责链模式存在以下两种情况。
- 单纯职责链模式:一个请求一定会被某个处理者处理,而且是单独处理。
- 复杂的职责链模式:一个请求不一定会被处理,可能会被多个处理者同时处理。
的逻辑。后续的使用仅仅需要创建不同级别的日志对象,再将不同的按照顺序放入下一个级别的属性parent
中。
拓展
职责链模式存在以下两种情况。
- 单纯职责链模式:一个请求一定会被某个处理者处理,而且是单独处理。
- 复杂的职责链模式:一个请求不一定会被处理,可能会被多个处理者同时处理。