C++ 责任链模式(Chain of Responsibility Pattern)
一、模式基础概述
1.1 定义
责任链模式属于行为型设计模式,将多个业务处理器以链表形式串联形成处理链路。请求从链路头部发起,依次交由每个节点判断处理权限;当前节点可自行处理请求,也可将请求向下一级节点转发,直至请求完成处理或链路终止。该模式彻底解绑请求发起方与实际处理方。
1.2 核心思想
弱化请求提交者与处理者的绑定关系,多个处理对象均具备处理请求的机会;按层级划分处理权限,逐级校验分发,按需终止转发,适配分级审批、逐层过滤类业务。
1.3 设计原则
- 单一职责:每个处理节点仅负责自身权限范围内的业务逻辑
- 开闭原则:新增处理节点无需修改原有链路代码,直接接入链条即可
- 迪米特法则:请求发起方无需知晓内部处理层级与流转细节
- 灵活组合:可动态调整节点顺序、增减节点,重构业务流程
二、核心组成角色
| 角色名称 | 核心职责 | C++ 实现形式 |
|---|---|---|
| 抽象处理者 Handler | 定义统一处理接口,维护后继处理节点指针,提供链路绑定方法 | 抽象基类,包含纯虚处理函数、设置下一级节点方法 |
| 具体处理者 ConcreteHandler | 实现专属业务判断与处理逻辑;权限不足则转发请求至下一节点 | 公有继承抽象处理类,重写处理接口 |
| 请求实体 Request | 封装请求携带的参数、类型、内容等业务数据 | 结构体/普通类,存储请求信息 |
| 客户端 Client | 组装责任链路,构造请求对象,向链头提交请求 | 业务调用入口、主函数 |
三、模式运行流程
- 客户端实例化所有层级处理节点,依次绑定上下级关系,构建完整责任链
- 封装业务请求数据,将请求发送至链路首个处理节点
- 当前节点判定自身是否具备处理资格
- 有权限则执行业务逻辑,流程结束;无权限则将请求转发下一级
- 逐级遍历节点,直到请求被处理、链路末尾终止或判定请求无效
四、经典业务示例:多级请假审批流程
cpp
#include <iostream>
#include <string>
#include <memory>
// 请假请求实体
struct LeaveRequest
{
std::string userName;
int leaveDays;
std::string leaveReason;
};
// 抽象审批处理者
class Approver
{
protected:
std::shared_ptr<Approver> nextApprover;
std::string approverName;
public:
explicit Approver(std::string name) : approverName(std::move(name)){}
virtual ~Approver() = default;
// 设置下一级审批人
void setNext(std::shared_ptr<Approver> next)
{
nextApprover = std::move(next);
}
// 抽象审批处理方法
virtual void handleRequest(const LeaveRequest& req) = 0;
};
// 组长审批:1-3天假期
class TeamLeader : public Approver
{
public:
using Approver::Approver;
void handleRequest(const LeaveRequest& req) override
{
if (req.leaveDays >= 1 && req.leaveDays <= 3)
{
std::cout << "组长【" << approverName << "】审批通过:"
<< req.userName << " 请假" << req.leaveDays << "天\n";
}
else if (nextApprover)
{
std::cout << "组长权限不足,向上转交审批\n";
nextApprover->handleRequest(req);
}
}
};
// 部门经理审批:4-7天假期
class DepartmentManager : public Approver
{
public:
using Approver::Approver;
void handleRequest(const LeaveRequest& req) override
{
if (req.leaveDays >= 4 && req.leaveDays <= 7)
{
std::cout << "部门经理【" << approverName << "】审批通过:"
<< req.userName << " 请假" << req.leaveDays << "天\n";
}
else if (nextApprover)
{
std::cout << "部门经理权限不足,向上转交审批\n";
nextApprover->handleRequest(req);
}
}
};
// 总经理审批:8-30天假期
class GeneralManager : public Approver
{
public:
using Approver::Approver;
void handleRequest(const LeaveRequest& req) override
{
if (req.leaveDays >= 8 && req.leaveDays <= 30)
{
std::cout << "总经理【" << approverName << "】审批通过:"
<< req.userName << " 请假" << req.leaveDays << "天\n";
}
else
{
std::cout << "请假天数超出最大限制,审批驳回\n";
}
}
};
// 客户端测试
int main()
{
// 构建审批链路
auto teamLead = std::make_shared<TeamLeader>("张三");
auto deptMgr = std::make_shared<DepartmentManager>("李四");
auto gm = std::make_shared<GeneralManager>("王五");
teamLead->setNext(deptMgr);
deptMgr->setNext(gm);
// 发起不同请假请求
LeaveRequest req1{"员工A", 2, "身体休养"};
LeaveRequest req2{"员工B", 6, "探亲访友"};
LeaveRequest req3{"员工C", 20, "婚嫁休假"};
LeaveRequest req4{"员工D", 35, "长途旅行"};
teamLead->handleRequest(req1);
std::cout << "-------------------------\n";
teamLead->handleRequest(req2);
std::cout << "-------------------------\n";
teamLead->handleRequest(req3);
std::cout << "-------------------------\n";
teamLead->handleRequest(req4);
return 0;
}
五、工程实战示例:分级日志过滤处理链
cpp
#include <iostream>
#include <string>
#include <memory>
// 日志级别定义
enum LogLevel
{
LOG_INFO = 1,
LOG_WARN = 2,
LOG_ERROR = 3
};
// 抽象日志处理器
class LogHandler
{
protected:
std::shared_ptr<LogHandler> nextHandler;
public:
virtual ~LogHandler() = default;
void setNext(std::shared_ptr<LogHandler> next)
{
nextHandler = std::move(next);
}
virtual void printLog(LogLevel level, const std::string& msg) = 0;
};
// 普通信息日志处理
class InfoLog : public LogHandler
{
public:
void printLog(LogLevel level, const std::string& msg) override
{
if (level == LOG_INFO)
{
std::cout << "[INFO] " << msg << std::endl;
}
else if (nextHandler)
{
nextHandler->printLog(level, msg);
}
}
};
// 警告日志处理
class WarnLog : public LogHandler
{
public:
void printLog(LogLevel level, const std::string& msg) override
{
if (level == LOG_WARN)
{
std::cout << "[WARN] " << msg << std::endl;
}
else if (nextHandler)
{
nextHandler->printLog(level, msg);
}
}
};
// 错误日志处理
class ErrorLog : public LogHandler
{
public:
void printLog(LogLevel level, const std::string& msg) override
{
if (level == LOG_ERROR)
{
std::cout << "[ERROR] " << msg << std::endl;
}
else if (nextHandler)
{
nextHandler->printLog(level, msg);
}
}
};
int main()
{
auto info = std::make_shared<InfoLog>();
auto warn = std::make_shared<WarnLog>();
auto error = std::make_shared<ErrorLog>();
// 组装日志处理链
info->setNext(warn);
warn->setNext(error);
// 提交不同级别日志
info->printLog(LOG_INFO, "系统初始化完成");
info->printLog(LOG_WARN, "内存占用即将达到阈值");
info->printLog(LOG_ERROR, "网络连接异常断开");
return 0;
}
六、责任链两种流转模式
6.1 唯一处理模式
请求被单个节点处理后立即终止转发,多级审批、权限校验常用该模式。
6.2 全链路遍历模式
请求流经所有处理节点,每个节点均可执行自身逻辑,过滤器、拦截器、日志打印场景适用。
七、模式优缺点
7.1 优点
- 请求方与处理方完全解耦,无需关心实际处理节点
- 层级逻辑拆分独立,单个节点功能单一,代码维护简单
- 支持动态调整链路节点顺序、增删处理器,业务扩展性强
- 规避大量if-else层级判断,代码结构更加规整
- 符合开闭原则,新增业务处理仅添加子类即可接入链路
7.2 缺点
- 链路配置失误会造成请求无法被处理,丢失业务数据
- 链路节点数量过多时,请求转发层级加深,执行效率下降
- 问题排查需要遍历整条链路,调试定位难度提升
- 节点间存在引用关系,构建链路时易出现循环依赖问题
八、适用业务场景
- 企业多级审批:请假、报销、采购、合同审核流程
- 日志分级分类输出、异常逐级上报处理
- Web服务中间件、接口权限校验、参数过滤拦截
- 界面事件逐级冒泡传递、按键事件分发
- 风控规则校验、数据逐层清洗过滤
- 机器人任务逐级审核、指令权限分发
九、相似设计模式对比
| 对比模式 | 核心特点 | 业务侧重 |
|---|---|---|
| 责任链模式 | 请求沿节点逐级转发,分层处理 | 分级审批、过滤拦截、层级分发 |
| 命令模式 | 将动作封装对象,支持队列、撤销 | 指令存储、任务调度、操作回滚 |
| 策略模式 | 整体替换算法逻辑,运行切换方案 | 算法择优、业务方案替换 |
| 观察者模式 | 事件一对多广播推送,被动接收 | 消息通知、状态同步、事件订阅 |
十、C++工程开发规范
- 采用
std::shared_ptr管理处理节点,安全管控对象生命周期 - 抽象基类统一封装下级节点绑定方法,标准化链路搭建流程
- 单个处理节点只实现一类业务逻辑,严格遵循单一职责
- 链路末尾设置兜底处理节点,避免请求无响应丢失
- 业务运行阶段禁止修改链路节点指向,防止流程错乱
- 超长链路拆分分段管理,减少单次转发层级,优化运行性能
十一、模式总结
责任链模式核心精髓为逐级分发、分层处理、解耦流转 。
依靠链表结构串联处理节点,按照权限与规则转发请求,把复杂的层级判断逻辑拆解为独立模块。既能灵活调整业务处理流程,又能降低模块耦合度,是审批系统、过滤拦截、事件分发类C++项目中高频使用的行为设计模式。