文章目录
- 简介
- 问题
- 解决
- 代码
- 核心改进点:
- 总结
简介
责任链是一种行为设计模式,允许你把请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。
问题
假如你正在开发一个订单系统。 你希望限制系统访问,只允许认证用户创建订单。 而管理员拥有所有订单的完全访问权限。
按照一般的开发思路,你会依次执行这些检查。 只要接收到包含用户凭据的请求,系统就可以尝试认证。 如果认证失败, 那就没有必要再进行后续检查了。如下图。
接着,关于认证检查的需求越来越多。比如为了不让原始数据直接传递到订单系统,需要在认证之后清理请求中的数据;比如为了对暴力密码破解或者爬虫请求进行限流,又需要在认证之后增加过滤来自同一 IP 地址的重复请求逻辑;比如为了提高系统响应速度,降低系统负载,又需要在请求发送给系统之前检查有没有缓存结果,如果没有才会把请求发送给系统。如下图,这部分逻辑就会越来越多,越来越混乱。
而且,修改某个检查步骤可能也会影响其他的检查步骤。 尤其是当你希望复用这些检查步骤来保护其他系统时,你只能复制部分代码, 因为这些系统只需要部分检查步骤。
解决
与许多其他行为设计模式一样, 责任链会把 特定行为转换成 叫做处理者的独立对象。 在上面示例里, 每个检查步骤都可以被抽取成仅有单个方法的类, 并执行检查操作。 请求和对应数据会被作为参数传递给这个方法。
这个模式建议你把这些处理者连成一条链。 链上的每个处理者都有一个成员变量来保存对于下一个处理者的引用。 除了处理请求外, 处理者还负责沿着链传递请求。 请求会在链上移动, 直到所有处理者都有机会对他进行处理。
更重要的是: 处理者可以决定不再沿着链传递请求, 这就可以高效地取消所有后面的处理步骤。
在我们的订单系统示例中, 处理者会在进行请求处理工作后决定要不要继续沿着链传递请求。 如果请求中包含正确的数据, 所有处理者都会执行自己的主要行为, 无论这个行为是身份验证还是数据缓存。
不过还有一种稍微不同的方式 (也是更经典一种), 那就是处理者接收到请求后自己决定是否能够对其进行处理。 如果自己能够处理, 处理者就不再继续传递请求。 因此在这种情况下, 每个请求要么最多有一个处理者进行处理, 要么没有任何处理者进行处理。 在处理图形用户界面元素栈中的事件时, 这种方式非常常见。另外,其实很多设计模式都是从很早用Java写客户端界面引出的解决方案。
代码
// Handler接口定义处理契约
public interface Handler {void handle(Request request) throws AuthException;
}// BaseHandler实现链式传递逻辑
public abstract class BaseHandler implements Handler {private Handler next;public BaseHandler setNext(Handler next) {this.next = next;return this;}protected void passToNext(Request request) throws AuthException {if (next != null) next.handle(request); // 核心链式调用逻辑}
}// 具体处理者1:用户认证
class UserAuthHandler extends BaseHandler {@Overridepublic void handle(Request request) throws AuthException {if (!validateUser(request.getUserId())) {throw new AuthException("用户未登录");}passToNext(request); // 验证成功移交后续处理}
}// 具体处理者2:权限校验
class PermissionHandler extends BaseHandler {@Override public void handle(Request request) throws AuthException {if (!checkAdminPermission(request.getUserId())) {throw new PermissionException("权限不足");}passToNext(request);}
}// Client动态组合处理链
public class OrderService {private Handler chain;public OrderService() {this.chain = new UserAuthHandler().setNext(new PermissionHandler()); // 灵活配置处理顺序}public void createOrder(Request request) {chain.handle(request); // 统一入口触发处理链// 执行业务逻辑...}
}
核心改进点:
- 解耦检查逻辑:每个安全检查独立成类,通过setNext组合链式结构
- 动态扩展性:新增日志检查仅需创建LogHandler并插入链中任意位置
- 复用性增强:在PaymentService中可重用UserAuthHandler而不需要重复验证代码
总结
- (Handler)声明了所有具体处理者的通用接口。这个接口通常只包含单个方法,用于请求处理,但有时它还会包含一个设置链上 下一个处理者 的方法。
- (Base Handler)是一个可选的类,你可以把所有处理者共用的样本代码放在里面。 通常情况下,这个类里定义了一个保存下个处理者引用的成员变量。客户端可以把下个处理者传递给上个处理者的构造函数或用setter方法 来创建链。这个类还可以实现默认的处理行为: 比如确定下个处理者存在后再把请求传递给它。
- (Concrete Handlers)包含处理请求的实际代码。每 个处理者接收到请求后,都必须决定要不要处理,以及要不要沿 着链传递请求。 处理者通常是独立并且不可变的,需要通过构造函数一次性地获得 所有必要的数据。
- (Client) 可根据程序逻辑一次性或者动态地生成链。 需要注意一下,请求可以发送给链上的任意一个处理者,不一定是第一个处理者。