概述
责任链模式 是一种行为设计模式, 允许你将请求沿着处理者链进行发送
。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者
。
该模式建议你将这些处理者连成一条链。
链上的每个处理者都有一个成员变量来保存对于下一处理者的引用
。 除了处理请求外, 处理者还负责沿着链传递请求。 请求会在链上移动, 直至所有处理者都有机会对其进行处理。
处理者可以决定不再沿着链传递请求
, 这可高效地取消所有后续处理步骤。
结构
示例
该模式在核心 Java 程序库中的一些示例:
- javax.servlet.Filter#doFilter()
- java.util.logging.Logger#log()
伪代码实现
Base Handler(基础处理者)
java
abstract class BaseHandler {
// 继任者
protected Handler successor;
public void setSuccesssor(Handler successor) {this.successor = successor;}
public static Handler link(Handler first, Handler... chain) {
Handler head = first; // 初始化头部为第一个中间件
for (Handler nextInChain : chain) {
head.setSuccesssor(nextInChain); // 将当前中间件的下一个指向链中的下一个中间件
head = nextInChain; // 移动到链中的下一个中间件
}
return first; // 返回链的头部
}
/**
* 子类将实现此方法以进行具体的检查。
*
* @param params 参数
* @return 返回检查结果
*/
public abstract boolean check(Object params);
/**
* 在链中的下一个对象上运行检查,或者如果我们在链的最后一个对象中则结束遍历。
*
* @param params 参数
* @return 如果没有下一个中间件,返回 true;否则返回下一个中间件的检查结果
*/
protected boolean checkNext(Object params) {
if (next == null) {
return true; // 如果没有下一个中间件,返回 true
}
return next.check(params); // 调用下一个中间件的检查方法
}
}
Handler(处理者)
Handler(处理者)
处理者1:校验请求次数限制
java
public class OneHandler extends BaseHandler {
private int requestPerMinute;
private int requestTimes;
private long currentTime;
public OneHandler(int requestPerMinute) {
this.requestPerMinute = requestPerMinute;
this.currentTime = System.currentTimeMillis();
}
/**
* 校验请求次数 一分钟内 是否到达requestPerMinute 达到则停止责任链
*/
public boolean check(Object params) {
if (System.currentTimeMillis() > currentTime + 60_000) {
request = 0;
currentTime = System.currentTimeMillis();
}
request++;
if (request > requestPerMinute) {
System.out.println("Request limit exceeded!");
Thread.currentThread().stop();
}
return super.checkNext(params);
}
}
处理者2:
java
public class TwoHandler extends BaseHandler {
private Server server;
public TwoHandler(Server server) {
this.server= server;
}
/**
* 校验其他
*/
public boolean check(Object params) {
server.checkOther(params);
// 其他处理
return super.checkNext(params);
}
}
Server(其他辅助service)
定义了handler中的其他处理方法等
java
public class Server {
private BaseHandler baseHandler;
public void setMiddleware(BaseHandler baseHandler) {
this.baseHandler = baseHandler;
}
public void checkOther(Object params) {
// 其他处理逻辑
}
public boolean test(Object params) {
if (baseHandler.check(params)) {
System.out.println("Authorization have been successful!");
// Do something useful here for authorized users.return true;
}
return false;
}
}
Client (客户端)
Client : 需要设置一个职责链的各环节对象串联起来。
java
public class ChainOfResponsibilityPattern {
public static void main(String[] args) {
BaseHandler handler = Middleware.link(
new OneHandler(2),
new TwoHandler(server)
);
server.test(params)
}
}
应用场景
当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式
- 该模式能将多个处理者连接成一条链。 接收到请求后, 它会 "询问" 每个处理者是否能够对其进行处理。 这样所有处理者都有机会来处理请求。
当必须按顺序执行多个处理者时, 可以使用该模式。
- 无论以何种顺序将处理者连接成一条链, 所有请求都会严格按照顺序通过链上的处理者。
如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式。
- 如果在处理者类中有对引用成员变量的设定方法, 你将能动态地插入和移除处理者, 或者改变其顺序。
实现方式
-
声明处理者接口
并描述请求处理方法的签名。- 确定客户端如何将请求数据传递给方法。 最灵活的方式是将请求转换为对象, 然后将其以参数的形式传递给处理函数。
-
在具体处理者中
消除重复的样本代码
, 你可以根据处理者接口创建抽象处理者基类。- 该类需要有一个
成员变量来存储指向链上下个处理者的引用
。 你可以将其设置为不可变类。 但如果你打算在运行时对链进行改变, 则需要定义一个设定方法来修改引用成员变量的值。 - 为了使用方便, 你还可以
实现处理方法的默认行为
。 如果还有剩余对象, 该方法会将请求传递给下个对象。 具体处理者还能够通过调用父对象的方法来使用这一行为。
- 该类需要有一个
-
依次
创建具体处理者子类并实现其处理方法
。 每个处理者在接收到请求后都必须做出两个决定:- 是否自行处理这个请求。
- 是否将该请求沿着链进行传递。
-
客户端可以自行组装链
, 或者从其他对象处获得预先组装好的链。 在后一种情况下, 你必须实现工厂类以根据配置或环境设置来创建链。客户端可以触发链中的任意处理者
, 而不仅仅是第一个。 请求将通过链进行传递, 直至某个处理者拒绝继续传递, 或者请求到达链尾。- 由于链的动态性, 客户端需要准备好处理以下情况:
链中可能只有单个链接
。- 部分
请求可能无法到达链尾
。 - 其他
请求可能直到链尾都未被处理
。