概述
职责链模式(Chain of Responsibility Pattern)是一种行为型设计模式,其核心思想是构建一个对象处理链,将请求从链的一端传递至另一端,链中的每个对象都拥有处理请求的权利和选择是否将请求转发给下一个对象的能力。
该模式彻底打破了“请求发送者与接收者强耦合”的传统逻辑,让请求在链中自动流转,直至找到能处理它的对象,实现了请求发送与处理的解耦,提升代码的灵活性和扩展性。在职责链模式中,每个处理对象仅需关注自身职责范围内的请求,无需知晓整个链的结构,也无需与其他处理对象直接交互。
这种设计不仅让单个处理逻辑更简洁,还能通过动态调整链的结构(新增、移除、调整处理对象顺序),灵活适配业务需求的变化。
核心价值
| 核心要点 | 详细说明 |
|---|---|
| 解耦请求关系 | 请求发送者无需知道具体由哪个对象处理请求,仅需将请求提交至链首,接收者也无需与发送者直接关联,彻底消除两者间的耦合依赖 |
| 灵活调整职责 | 可通过动态增删处理对象、调整对象在链中的顺序,快速适配业务变化,无需修改原有处理逻辑和请求发送代码,符合“开放-封闭原则” |
| 单一职责强化 | 每个处理对象仅负责处理特定范围的请求,职责边界清晰,代码可读性和可维护性大幅提升,便于后续迭代优化 |
| 请求流转可控 | 请求在链中按预设顺序流转,可根据业务需求控制请求是否终止传递、是否多对象协同处理,流转逻辑灵活可控 |
适用场景
| 场景类型 | 具体说明 |
|---|---|
| 多规则校验场景 | 如接口请求参数校验(非空校验、格式校验、权限校验、业务规则校验等),每个校验规则作为一个处理节点,依次执行校验 |
| 分级审批场景 | 如报销单审批(普通员工报销→部门经理审批→财务审批→总经理审批),不同金额或类型的报销单流转至对应层级审批 |
| 多渠道处理场景 | 如异常日志处理(本地日志记录→邮件告警→短信通知→运维平台上报),根据异常级别选择不同处理渠道,或依次执行多渠道处理 |
| 动态职责分配场景 | 业务需求中处理逻辑可能频繁增减或调整顺序,如订单状态流转处理、消息路由分发等场景 |
注意事项
| 注意点 | 具体说明 |
|---|---|
| 避免链过长导致性能损耗 | 若职责链节点过多,请求需经过多次传递才能找到处理对象,会增加系统响应时间,需合理控制链的长度 |
| 防止请求“丢失” | 需确保每个请求都能在链中找到对应的处理对象,或设置链尾默认处理节点(如异常兜底处理),避免请求无人处理 |
| 明确节点处理范围 | 每个处理节点的职责边界需清晰,避免出现重复处理或处理范围重叠的情况,导致逻辑混乱 |
| 谨慎设计链结构 | 避免构建环形链(节点间相互引用),导致请求无限循环流转,需在代码中加入循环检测或超时控制机制 |
完整代码
以“订单退款申请审批”为业务场景,构建职责链模式实现:不同金额的退款申请需流转至对应层级审批(普通客服→部门主管→财务经理),超过设定金额则拒绝退款。
<?php
declare(strict_types = 1);
/**
* 抽象处理者:定义职责链节点的统一接口
*/
abstract class RefundHandler
{
/**
* 下一个处理者
* @var RefundHandler|null
*/
protected ?RefundHandler $nextHandler = null;
/**
* 设置下一个处理者,构建职责链
* @param RefundHandler $handler
* @return RefundHandler
*/
public function setNextHandler(RefundHandler $handler): RefundHandler
{
$this->nextHandler = $handler;
return $handler; // 支持链式调用设置节点
}
/**
* 抽象处理方法:子类必须实现具体处理逻辑
* @param float $amount 退款金额
* @param string $orderNo 订单号
* @return string
*/
abstract public function handle(float $amount, string $orderNo): string;
}
/**
* 具体处理者1:普通客服(处理金额≤100元的退款)
*/
class CustomerService extends RefundHandler
{
public function handle(float $amount, string $orderNo): string
{
// 自身职责范围:处理100元及以下退款
if ($amount <= 100) {
return sprintf(
"订单【%s】- 退款金额%.2f元,由普通客服审批通过,已发起退款流程。",
$orderNo,
$amount
);
}
// 超出职责范围,传递给下一个处理者
if ($this->nextHandler !== null) {
return $this->nextHandler->handle($amount, $orderNo);
}
// 无下一个处理者,返回无法处理信息
return sprintf("订单【%s】- 退款金额%.2f元,无对应审批节点,退款失败。", $orderNo, $amount);
}
}
/**
* 具体处理者2:部门主管(处理100元<金额≤500元的退款)
*/
class DepartmentManager extends RefundHandler
{
public function handle(float $amount, string $orderNo): string
{
// 自身职责范围:处理100-500元退款
if ($amount > 100 && $amount <= 500) {
return sprintf(
"订单【%s】- 退款金额%.2f元,由部门主管审批通过,已发起退款流程。",
$orderNo,
$amount
);
}
// 超出职责范围,传递给下一个处理者
if ($this->nextHandler !== null) {
return $this->nextHandler->handle($amount, $orderNo);
}
// 无下一个处理者,返回无法处理信息
return sprintf("订单【%s】- 退款金额%.2f元,无对应审批节点,退款失败。", $orderNo, $amount);
}
}
/**
* 具体处理者3:财务经理(处理500元<金额≤1000元的退款)
*/
class FinanceManager extends RefundHandler
{
public function handle(float $amount, string $orderNo): string
{
// 自身职责范围:处理500-1000元退款
if ($amount > 500 && $amount <= 1000) {
return sprintf(
"订单【%s】- 退款金额%.2f元,由财务经理审批通过,已发起退款流程。",
$orderNo,
$amount
);
}
// 超出职责范围,传递给下一个处理者(若有),若无则拒绝
if ($this->nextHandler !== null) {
return $this->nextHandler->handle($amount, $orderNo);
}
// 超出最大可审批金额,直接拒绝
return sprintf("订单【%s】- 退款金额%.2f元,超出最大审批额度(1000元),退款拒绝。", $orderNo, $amount);
}
}
// 测试代码
try {
// 1. 创建各个处理节点
$customerService = new CustomerService();
$deptManager = new DepartmentManager();
$financeManager = new FinanceManager();
// 2. 构建职责链:普通客服 → 部门主管 → 财务经理
$customerService->setNextHandler($deptManager)->setNextHandler($financeManager);
// 3. 测试不同金额的退款请求
echo $customerService->handle(80.5, "OD20260106001") . "<br/>";
echo $customerService->handle(350.0, "OD20260106002") . "<br/>";
echo $customerService->handle(880.2, "OD20260106003") . "<br/>";
echo $customerService->handle(1200.0, "OD20260106004") . "<br/>";
} catch (\Exception $e) {
echo "退款处理异常:" . $e->getMessage();
}
核心结构拆解
职责链模式的核心由“抽象处理者”和“具体处理者”两部分组成,结构清晰且易于扩展:
| 结构组成 | 详细说明 |
|---|---|
| 抽象处理者(RefundHandler) | 定义职责链节点的统一规范,包含“设置下一个处理者”和“处理请求”两个核心方法。其中 setNextHandler 用于构建链式结构,handle 为抽象方法,由子类实现具体处理逻辑。 |
| 具体处理者(CustomerService、DepartmentManager 等) | 继承抽象处理者,实现 handle 方法,判断请求是否在自身职责范围内。若能处理则直接返回结果,若不能则将请求传递给下一个处理者,直至链尾。 |
| 链的构建 | 客户端通过调用 setNextHandler 方法,按业务逻辑顺序串联各个具体处理者,形成完整的职责链。请求从链首节点进入,自动流转至对应处理者。 |
关键优化点
| 优化方向 | 详细说明 |
|---|---|
| 支持链式调用构建 | setNextHandler 方法返回下一个处理者对象,允许客户端以链式语法快速构建职责链(如 $customerService->setNextHandler($deptManager)->setNextHandler($financeManager)),代码更简洁。 |
| 明确职责边界 | 每个具体处理者仅处理特定范围的请求,通过条件判断严格区分职责,避免处理逻辑混乱,符合单一职责原则。 |
| 链尾兜底处理 | 在每个具体处理者中加入“无下一个处理者”的判断,针对超出链处理能力的请求返回明确提示,避免请求丢失或报错。 |
| 类型安全强化 | 通过严格类型声明(参数类型、返回值类型),提升代码可读性和稳定性,避免因类型错误导致的逻辑异常。 |
常见错误规避
| 错误类型 | 问题描述及解决方案 |
|---|---|
| 未设置链尾兜底 | 问题:若链尾处理者未对超出职责范围的请求做处理,会导致请求流转后无返回结果,甚至引发空指针异常。 解决:在链尾处理者中加入兜底逻辑(如拒绝请求、默认处理)。 |
| 构建环形链 | 问题:若处理者节点相互引用(如 A→B→C→A),会导致请求无限循环流转,耗尽系统资源。 解决:构建链时需校验节点关系,避免环形依赖,或加入请求流转次数限制。 |
| 处理逻辑耦合 | 问题:具体处理者中嵌入其他处理者的逻辑,导致节点间耦合度高,难以扩展。 解决:严格遵循抽象处理者定义的接口,每个节点仅关注自身职责,不依赖其他节点的实现。 |
| 链结构固定化 | 问题:将链的构建逻辑硬编码在客户端,导致无法动态调整。 解决:可封装链构建工厂类,根据业务参数动态生成职责链,提升灵活性。 |
扩展场景示例(动态调整链结构)
若业务新增“VIP客户专属审批通道”(VIP客户退款金额≤200元可由普通客服直接审批),仅需新增具体处理者并调整链结构,无需修改原有代码:
// 新增具体处理者:VIP客户客服
class VipCustomerService extends RefundHandler
{
public function handle(float $amount, string $orderNo): string
{
// 仅处理VIP客户200元及以下退款(此处简化逻辑,实际可结合用户身份判断)
if ($amount <= 200) {
return sprintf(
"订单【%s】- VIP客户专属通道,退款金额%.2f元,由VIP客服审批通过,已发起退款流程。",
$orderNo,
$amount
);
}
if ($this->nextHandler !== null) {
return $this->nextHandler->handle($amount, $orderNo);
}
return sprintf("订单【%s】- 退款金额%.2f元,无对应审批节点,退款失败。", $orderNo, $amount);
}
}
// 构建VIP客户专属职责链
$vipService = new VipCustomerService();
$vipService->setNextHandler($financeManager); // VIP客服→财务经理
echo $vipService->handle(180.0, "OD20260106005") . "<br/>"; // VIP客户180元退款
实际应用场景
| 场景分类 | 具体说明 |
|---|---|
| 请求参数校验 | 接口请求进入后端后,依次经过非空校验、格式校验、权限校验、业务规则校验等节点,每个节点仅负责一项校验,校验通过则进入下一级,失败则返回错误信息。 |
| 日志级别处理 | 系统日志按级别(DEBUG、INFO、WARN、ERROR)构建处理链,不同级别日志对应不同处理逻辑(如DEBUG日志本地记录、ERROR日志邮件告警+平台上报)。 |
| 订单状态流转 | 订单从“待支付”到“已完成”的状态变更,需经过支付验证、库存扣减、物流创建、积分发放等节点,每个节点处理完成后传递至下一个节点,形成完整的业务链。 |
职责链模式与其他模式对比
| 对比维度 | 职责链模式 | 观察者模式 | 策略模式 |
|---|---|---|---|
| 核心目标 | 请求在链中流转,找到对应处理者 | 主题状态变更,通知所有观察者 | 封装不同算法,动态切换执行 |
| 对象关系 | 链式结构,节点间单向依赖 | 一对多,主题依赖观察者接口 | 一对一,上下文依赖策略接口 |
| 执行逻辑 | 请求流转,单个对象处理 | 通知分发,多个对象同时处理 | 选择一种算法,单独执行 |
| 适用场景 | 多节点分级处理、规则校验 | 事件触发多后续操作 | 算法动态切换、逻辑替换 |


