责任链模式是一种行为型设计模式,用于构建一条处理请求的链。在这个链上的每个处理器都有机会处理请求,如果一个处理器不能处理请求,则将请求传递给下一个处理器,直到有一个处理器能够处理它。
问题
假如你正在开发一个在线订购系统。 你希望对系统访问进行限制, 只允许认证用户创建订单。 此外, 拥有管理权限的用户也拥有所有订单的完全访问权限。
简单规划后, 你会意识到这些检查必须依次进行。 只要接收到包含用户凭据的请求, 应用程序就可尝试对进入系统的用户进行认证。 但如果由于用户凭据不正确而导致认证失败, 那就没有必要进行后续检查了。
一段时间后你发现几个问题并有了新的解决方案:
- 系统无法抵御暴力密码破解方式的攻击。 为了防范这种情况, 你立刻添加了一个检查步骤来过滤来自同一 IP 地址的重复错误请求。
- 直接将原始数据传递给订购系统存在安全隐患。 因此你新增了额外的验证步骤来清理请求中的数据。
- 可以对包含同样数据的重复请求返回缓存中的结果,从而提高系统响应速度。 因此, 你新增了一个检查步骤, 确保只有没有满足条件的缓存结果时请求才能通过并被发送给系统。
随着代码迭代,系统会变得让人非常费解, 而且其维护成本也会激增。 你在艰难地和这些代码共处一段时间后, 有一天终于决定对整个系统进行重构
解决方案
在我们的订购系统示例中, 处理者会在进行请求处理工作后决定是否继续沿着链传递请求。 如果请求中包含正确的数据, 所有处理者都将执行自己的主要行为, 无论该行为是身份验证还是数据缓存。
结构
-
抽象处理器(Handler): 定义处理请求的接口,并持有下一个处理器的引用。
-
具体处理器(Concrete Handler): 实现处理请求的具体逻辑,并决定是否将请求传递给下一个处理器。
示例
下面是一个简单的责任链模式的示例代码:
在这个示例中,Handler 是抽象处理器,ConcreteHandler1 和 ConcreteHandler2 是具体处理器。客户端将请求发送给第一个处理器,处理器链中的每个处理器根据自己的逻辑来决定是否处理请求或将请求传递给下一个处理器。
// 抽象处理器
abstract class Handler {
protected Handler nextHandler; // 下一个处理器
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public abstract void handleRequest(int request); // 处理请求的抽象方法
}
// 具体处理器1
class ConcreteHandler1 extends Handler {
public void handleRequest(int request) {
if (request >= 0 && request < 10) {
System.out.println("ConcreteHandler1 handles request: " + request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request); // 将请求传递给下一个处理器
}
}
}
// 具体处理器2
class ConcreteHandler2 extends Handler {
public void handleRequest(int request) {
if (request >= 10 && request < 20) {
System.out.println("ConcreteHandler2 handles request: " + request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request); // 将请求传递给下一个处理器
}
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 构建处理器链
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
handler1.setNextHandler(handler2);
// 发送请求
handler1.handleRequest(5);
handler1.handleRequest(15);
handler1.handleRequest(25);
}
}
优点
-
解耦性增强: 请求发送者和接收者之间的解耦,请求发送者不需要知道具体的处理者,处理者也不需要知道请求的发送者。
-
灵活性提高: 可以动态地调整链中处理器的顺序,灵活地改变请求的处理流程。
-
可扩展性增加: 可以很容易地增加新的处理器来处理新的请求类型。
缺点
-
性能问题: 处理请求时可能需要遍历整个链,可能会影响性能。
-
请求未被处理: 如果没有处理器能够处理请求,则请求会被丢弃,可能会造成请求未被处理的情况。
应用场景
-
多级审批流程: 如请假审批、报销审批等流程。
-
事件处理: 如GUI事件处理、日志处理等。