职责链模式核心结构是抽象基类Handler含虚函数handle()和std::unique_ptr next_handler_,通过set_next()链式组装;需避免裸指针、空解引用,推荐std::optional返回结果,固定短流程或强依赖场景不宜使用。

职责链模式的核心结构怎么写
职责链本质是把多个处理逻辑串成一条链,每个节点决定是否处理请求、是否继续往下传。C++里最直接的方式是定义一个抽象基类 Handler,带虚函数 handle() 和指向下一个处理器的指针 next_handler_。
关键点在于:每个子类只关心自己的处理条件,不硬编码后续逻辑;链的组装由外部控制,不是在类内部写死。
-
handle()必须是虚函数,且通常返回bool(表示是否已处理完毕),否则无法实现“中断传递”或“继续转发” -
set_next()接口要返回*this(支持链式调用),避免每次都要写a->set_next(b); b->set_next(c); - 不要在基类构造函数里自动连接下一级——这会让链失去灵活性,也违背开闭原则
怎么避免内存泄漏和空指针崩溃
常见错误是手动 new 一堆 Handler 子类对象,又忘了 delete;或者调用 next_handler_->handle() 前没判空,一触发就 SEGFAULT。
推荐做法是统一用 std::unique_ptr 管理所有权,并在 handle() 中显式检查:
bool ConcreteHandlerA::handle(const Request& req) {
if (req.type != "A") {
return next_handler_ ? next_handler_->handle(req) : false;
}
// 处理逻辑...
return true;
}
- 所有
next_handler_成员声明为std::unique_ptr,构造时用std::make_unique - 禁止裸指针传参构建链——容易导致悬挂指针,尤其在容器里移动对象时
- 如果链需要运行时动态重组(比如插删中间节点),改用
std::shared_ptr,但得小心循环引用
std::optional 或返回值类型怎么选
原生职责链返回 bool 只能表达“处理了/没处理”,但实际业务常需要返回结果(比如解析后的数据、错误码)。这时候别硬塞进全局变量或输出参数。
更现代的做法是让 handle() 返回 std::optional:
std::optional<parseddata> JsonHandler::handle(const std::string& raw) {
if (!starts_with(raw, "{")) return std::nullopt;
return parse_json(raw);
}</parseddata>
- 调用方可以自然地用
if (auto res = handler->handle(input)) { ... }检查并解包 - 比抛异常轻量,比布尔值信息丰富,也比自定义状态枚举更易扩展
- 注意:如果链中某环必须返回非空结果(比如日志必须落盘),那就不能用
std::optional,得换回Result风格(如absl::StatusOr)
什么时候不该用职责链
职责链看着优雅,但真用错场景反而增加复杂度。下面这些情况建议绕开:
- 处理步骤固定且总数少(比如只有 2–3 步)——直接写 if-else 更快、更易调试
- 各环节强依赖前序结果(比如 B 必须用 A 的输出做输入)——这时更适合管道模式(
auto out = B(A(in))) - 性能敏感路径(如游戏帧更新、高频网络包解析)——虚函数调用+指针跳转有不可忽略开销,可考虑模板化静态链(
Chain) - 需要精确控制执行顺序或回溯(比如某个环节失败要倒着清理)——职责链天然单向,不适合双向协调
链越长,调试时越难定位是哪个环节吞掉了请求或返回了意外的 false。上线前务必给每个 Handler 加上可开关的日志钩子。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











