什么是责任链模式(Chain of Responsibility Pattern)
责任链模式旨在避免将请求的发送者与接收者耦合在一起,让多个对象都有机会处理该请求。它将这些接收对象连接成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
想象一个公司的报销审批流程:
- 员工提交报销单(请求 Request)。
- 首先由直属经理(处理器 Handler 1)审批。如果金额在经理的权限范围内,经理处理(批准或拒绝),流程结束。
- 如果金额超出经理权限,请求会沿着链条传递给部门主管(处理器 Handler 2)。主管检查是否在其权限内,是则处理,否则继续传递。
- 以此类推,请求可能最终到达财务总监或 CEO(处理器 Handler N)。
在这个过程中,提交报销单的员工(发送者 Client)不需要知道具体是哪一级领导会处理它,只需要将请求交给链的起点。每个处理器也只关心自己能否处理,以及知道下一个处理器是谁(如果自己不能处理)。
责任链模式的核心在于构建一个处理器链,让请求在链上传递,直到被处理。
核心思想
- 定义处理器接口/抽象类 (Handler): 定义一个处理请求的接口,通常包含一个 handleRequest(request) 方法。它也常常包含一个指向链中下一个处理器(successor)的引用。
- 创建具体处理器 (ConcreteHandler): 实现 Handler 接口/继承抽象类。每个具体处理器:
- 判断自己是否能够处理传入的请求。
- 如果能处理,则处理请求,并且通常不再将请求向后传递(这是最常见的实现方式,但也有变种允许继续传递)。
- 如果不能处理,则将请求转发给它的后继者 (successor.handleRequest(request)),前提是后继者存在。
- 构建链条: 客户端 (Client) 负责创建处理器对象,并将它们按照特定的顺序连接起来,形成责任链。通常通过设置每个处理器的 successor 引用来完成。
- 发起请求: 客户端将请求发送给链的第一个处理器。
优点
- 降低耦合度 (Reduced Coupling): 请求的发送者和接收者解耦。发送者不需要知道是哪个对象最终处理了请求。处理器之间也只需要知道自己的直接后继者(或者根本不知道,由链结构决定)。
- 增强了灵活性 (Increased Flexibility): 可以很容易地在不影响客户端的情况下,修改链的结构(增加、删除、重排处理器),或者动态地改变处理器的职责。符合开闭原则。
- 简化了对象: 每个处理器只需要关注自己能处理的请求,以及如何将不能处理的请求传递下去,职责更单一。
- 请求分发透明: 请求的发送和处理过程对发送者来说是透明的。
可能的缺点
- 请求不保证被处理: 如果链条配置不当,或者没有任何处理器能够处理某个特定请求,该请求可能会到达链的末端而未被处理。
- 性能影响: 在链条较长的情况下,请求需要经过多个处理器的判断和传递,可能会影响性能。尤其是在每个节点的处理逻辑都比较耗时的情况下。
- 调试困难: 如果链条复杂,追踪请求的处理过程和定位问题可能比较困难。
使用场景
- 当有多个对象可以处理同一个请求,但具体由哪个对象处理在运行时动态确定时。
- 当你想在不明确指定接收者的情况下,向多个对象中的一个提交请求时。
- 当需要动态指定一组对象处理请求的顺序时。
- 事件处理机制: UI 事件的冒泡或捕获机制(如 Android 的触摸事件分发)。事件从触发点开始,沿着视图树向上传递(冒泡)或向下传递(捕获),每个视图层级都有机会处理或拦截事件。
- Web 服务器的中间件/过滤器 (Middleware/Filters): 请求在到达最终处理程序之前,会经过一系列中间件(如身份验证、日志记录、数据压缩),每个中间件处理完自己的任务后,决定是将请求传递给下一个中间件还是直接返回响应。
- 日志系统: 不同级别的日志处理器可以形成链,根据日志级别决定是否处理该日志记录。
- 审批流程: 如开头的报销审批例子。
- Android 中的场景:
- 触摸事件分发 (dispatchTouchEvent, onInterceptTouchEvent, onTouchEvent): 这是 Android 中最经典的责任链应用。触摸事件首先由 Activity 分发给根 ViewGroup,然后沿着视图树向下传递(dispatchTouchEvent -> onInterceptTouchEvent)。如果某个 ViewGroup 拦截了事件,则事件交由它的 onTouchEvent 处理;如果不拦截,则继续向下传递给子 View。如果子 View 的 onTouchEvent 返回 true (表示已处理),事件就此终结;如果返回 false,事件会反向冒泡回父 ViewGroup 的 onTouchEvent。这个过程形成了一个复杂的、双向的责任链。
- OkHttp Interceptors: OkHttp 网络库的拦截器机制。你可以添加多个拦截器(如日志拦截器、缓存拦截器、认证拦截器),它们形成一个链。每个拦截器可以处理请求/响应,然后调用 chain.proceed(request) 将控制权交给链中的下一个拦截器。
- 自定义权限检查: 可以构建一个权限检查链,例如先检查基本权限,再检查特定功能权限,最后检查用户角色权限。
UML 图
下面是基于“审批流程”示例的责任链模式 UML 图:
- Request: 代表需要被处理的请求(例如报销单)。
- Approver (Handler): 抽象处理器,定义了处理请求的接口 handleRequest 和设置后继者的方法 setSuccessor,并持有 successor 引用。
- ManagerApprover, DirectorApprover, VicePresidentApprover (ConcreteHandler): 具体的审批者。它们实现了 handleRequest 方法。在该方法中,它们检查请求金额是否在自己的审批权限 (approvalLimit) 内。如果是,则处理请求;否则,将请求传递给 successor(如果存在)。
- Client: 创建审批者实例,设置它们的 successor 关系来构建责任链,然后创建 Request 对象并将其发送给链的第一个处理器(例如 ManagerApprover)。
代码示例
在这个例子中:
- ExpenseReport 是请求对象。
- Approver 是抽象 Handler。
- ManagerApprover, DirectorApprover, VicePresidentApprover 是 Concrete Handlers,各自有不同的审批上限。
- main 函数(Client)创建了审批者实例,并用 setSuccessor 将它们连接成 Manager -> Director -> VP 的链条。
- 不同的报销请求被发送给链的起点 (manager),然后根据金额沿着链条传递,直到被合适的审批者处理或到达链的末端。
总结
- 责任链模式通过构建处理器链来解耦请求发送者和接收者。
- 请求沿着链传递,直到链中的某个处理器处理它为止,这提供了很大的灵活性来组织和修改处理逻辑。
- 需要注意请求可能最终不被处理的情况,以及长链条可能带来的性能问题。
- 在 Android 中,触摸事件分发和 OkHttp 拦截器是理解和应用此模式的绝佳范例。
记住它的核心:请求像接力棒,沿着链条往下传,谁能处理谁接手。
- Author:CoderWdd
- URL:https://www.wuinsights.top//article/1253ae73-3b94-495b-9d41-87b4e70f049d
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts