责任链模式
责任链模式允许你将请求沿着处理者链进行发送,每个处理者均可对请求进行处理或将其传递给链上的下个处理者。
假如你正在开发一个在线订购系统。你希望对系统访问进行限制,只允许认证用户创建订单。此外,拥有管理权限的用户也拥有所有订单的完全访问权限。简单规划后,你会意识到这些检查必须依次进行。只要接收到包含用户凭据的请求,应用程序就可尝试对进入系统的用户进行认证。但如果由于用户凭据不正确而导致认证失败,那就没有必要进行后续检查了。
在接下来的几个月里, 你实现了后续的几个检查步骤:
- 一位同事认为直接将原始数据传递给订购系统存在安全隐患。因此你新增了额外的验证步骤来清理请求中的数据。
- 过了一段时间,有人注意到系统无法抵御暴力密码破解方式的攻击。为了防范这种情况,你立刻添加了一个检查步骤来过滤来自同一 IP 地址的重复错误请求。
- 又有人提议你可以对包含同样数据的重复请求返回缓存中的结果,从而提高系统响应速度。因此,你新增了一个检查步骤,确保只有没有满足条件的缓存结果时请求才能通过并被发送给系统。
检查代码本来就已经混乱不堪,而每次新增功能都会使其更加臃肿。修改某个检查步骤有时会影响其他的检查步骤。最糟糕的是,当你希望复用这些检查步骤来保护其他系统组件时,你只能复制部分代码,因为这些组件只需部分而非全部的检查步骤。
系统会变得让人非常费解,而且其维护成本也会激增。你在艰难地和这些代码共处一段时间后,有一天终于决定对整个系统进行重构。
与许多其他行为设计模式一样,责任链会将特定行为转换为被称作处理者的独立对象。在上述示例中,每个检查步骤都可被抽取为仅有单个方法的类,并执行检查操作。请求及其数据则会被作为参数传递给该方法。责任链模式建议你将这些处理者连成一条链,链上的每个处理者都有一个成员变量来保存对于下一处理者的引用。除了处理请求外,处理者还负责沿着链传递请求。请求会在链上移动,直至所有处理者都有机会对其进行处理。最重要的是,处理者可以决定不再沿着链传递请求,这可高效地取消所有后续处理步骤。
不过还有一种稍微不同的方式(也是更经典的一种),那就是处理者接收到请求后自行决定是否能够对其进行处理。如果自己能够处理,处理者就不再继续传递请求。因此在这种情况下,每个请求要么最多有一个处理者对其进行处理,要么没有任何处理者对其进行处理。在处理图形用户界面元素栈中的事件时,这种方式非常常见。这时,责任链就有点像策略模式了。
import java.util.ArrayList;
import java.util.List;
// 请求类,包含用户凭据和请求数据
class Request {
private String credentials;
private String ipAddress;
private String data;
private boolean authenticated;
private boolean isAdmin;
public Request(String credentials, String ipAddress, String data) {
this.credentials = credentials;
this.ipAddress = ipAddress;
this.data = data;
}
// Getters and Setters
}
// 抽象处理器
abstract class Handler {
protected Handler next;
public Handler setNext(Handler next) {
this.next = next;
return next;
}
public abstract boolean handle(Request request);
}
// 认证处理器
class AuthenticationHandler extends Handler {
@Override
public boolean handle(Request request) {
// 模拟认证逻辑
if (!isValidCredentials(request.getCredentials())) {
System.out.println("认证失败:无效的用户凭据");
return false;
}
request.setAuthenticated(true);
// 模拟设置管理员权限
if ("admin_token".equals(request.getCredentials())) {
request.setAdmin(true);
}
System.out.println("认证成功");
return next == null || next.handle(request);
}
private boolean isValidCredentials(String credentials) {
// 模拟凭证验证
return credentials != null &&
(credentials.equals("user_token") || credentials.equals("admin_token"));
}
}
// 数据清理处理器
class DataSanitizationHandler extends Handler {
@Override
public boolean handle(Request request) {
if (!request.isAuthenticated()) {
return false;
}
// 模拟数据清理逻辑
String sanitizedData = sanitizeData(request.getData());
System.out.println("数据清理完成");
return next == null || next.handle(request);
}
private String sanitizeData(String data) {
// 模拟数据清理过程
return data.replaceAll("<script>", "");
}
}
// IP过滤处理器
class IPFilterHandler extends Handler {
private List<String> blockedIPs = new ArrayList<>();
@Override
public boolean handle(Request request) {
if (!request.isAuthenticated()) {
return false;
}
// 模拟IP过滤逻辑
if (isBlockedIP(request.getIpAddress())) {
System.out.println("访问被拒绝:IP地址已被屏蔽");
return false;
}
System.out.println("IP检查通过");
return next == null || next.handle(request);
}
private boolean isBlockedIP(String ipAddress) {
// 模拟IP黑名单检查
return blockedIPs.contains(ipAddress);
}
}
// 缓存检查处理器
class CacheHandler extends Handler {
@Override
public boolean handle(Request request) {
if (!request.isAuthenticated()) {
return false;
}
// 模拟缓存检查逻辑
if (hasCachedResult(request)) {
System.out.println("返回缓存结果");
return true; // 有缓存结果,直接返回,不继续传递
}
System.out.println("无缓存结果,继续处理");
return next == null || next.handle(request);
}
private boolean hasCachedResult(Request request) {
// 模拟缓存检查
return false; // 默认无缓存
}
}
// 订单处理处理器(责任链的终点)
class OrderProcessingHandler extends Handler {
@Override
public boolean handle(Request request) {
if (!request.isAuthenticated()) {
return false;
}
// 模拟订单处理逻辑
System.out.println("订单处理完成");
return true;
}
}
// 客户端代码
public class ChainOfResponsibilityDemo {
public static void main(String[] args) {
// 构建责任链
Handler authentication = new AuthenticationHandler();
Handler sanitization = new DataSanitizationHandler();
Handler ipFilter = new IPFilterHandler();
Handler cache = new CacheHandler();
Handler orderProcessing = new OrderProcessingHandler();
authentication.setNext(sanitization)
.setNext(ipFilter)
.setNext(cache)
.setNext(orderProcessing);
// 测试请求
System.out.println("=== 测试1:正常用户请求 ===");
Request userRequest = new Request("user_token", "192.168.1.1", "订单数据");
authentication.handle(userRequest);
System.out.println("\n=== 测试2:管理员请求 ===");
Request adminRequest = new Request("admin_token", "192.168.1.2", "订单数据");
authentication.handle(adminRequest);
System.out.println("\n=== 测试3:无效凭证请求 ===");
Request invalidRequest = new Request("invalid_token", "192.168.1.3", "订单数据");
authentication.handle(invalidRequest);
}
}
责任链模式和策略模式有点像,他们的区别是:
- 策略模式: 一个请求只能由一个策略类处理,客户端选择使用哪个策略
- 责任链模式: 一个请求可以由多个处理器依次处理,每个处理器决定是否处理请求和是否传递