广告

C++如何实现责任链模式:行为型设计模式Chain of Responsibility源码解析

在C++中实现责任链模式的基本思想

行为型设计模式与责任链的定位

责任链模式属于行为型设计模式之一,核心在于将请求沿着一条处理者链传递,直到有一个处理者对其做出处理或链条末端的默认行为被触发。职责分离请求分发是此模式的关键,发送者无需知道谁来处理请求,处理者也无需知道请求的全部来源。通过将处理职责沿链分散,可以达到高内聚、低耦合的设计目标。

在C++中实现责任链,通常会建立一个抽象的处理者接口,定义一个用于传递下一个处理者的指针或智能指针,以及一个虚拟的处理方法。通过多态机制,不同的具体处理者实现各自的处理逻辑,若自己不能处理则将请求转发给链上的下一个处理者,直到链条结束。此处的实现强调链路的动态组装可扩展性

需要注意的是,责任链虽然提升了解耦和可维护性,但也要控制链条长度、避免无限循环,并在设计时考虑终止条件、错误处理与日志记录等辅助机制,以确保系统的鲁棒性。本文中的实现思路正是围绕解耦、扩展性与可控的传递行为来展开的。

设计要点与实现要点

抽象处理者与具体处理者

核心思想是定义一个抽象处理者接口,包含一个指向下一个处理者的指针以及一个对外公开的处理入口。通过抽象类(接口)实现对处理流程的统一约束,便于后续扩展新的处理者。与此同时,具体处理者只需实现自己的逻辑,遵循单一职责原则即可。

在实现层面,通常会提供一个 setNextsetNextHandler 的方法来组装链条,以及一个 handle 的方法用于执行处理。这样客户端就可以按需动态拼接处理链,达到可配置的处理顺序

通过将请求的处理权交给构建好的链条,系统能够在不修改客户端代码的情况下增加新的处理步骤,这正是可扩展性解耦性的体现。

如何组织链条与传递责任

链条的顺序直接决定了处理的优先级:越靠前的处理者越先尝试处理请求,若处理失败则继续传递给下一个处理者。为了实现可靠的传递,需要为每个处理者提供一个明确的传递逻辑,常见做法是:若当前处理者能够处理则返回成功,否则将请求交由下一个处理者继续处理。此过程的关键点在于链路的流转性终止条件的明确。

实现层面还可以引入组装工厂或建造者模式,以便将复杂的处理链在创建阶段就完成,减少运行时的耦合。对于需要回退或补偿的场景,可以在链末端引入默认处理行为,确保请求不会永久丢失。以上设计要点共同构成了一个可维护、可扩展的处理体系。链条的可配置性鲁棒的终止条件是实现的关键。

C++如何实现责任链模式:行为型设计模式Chain of Responsibility源码解析

源码解析:核心类与关系

Handler接口与职责传递

从源码角度看,责任链的核心在于一个抽象处理者类,它维护一个指向下一处理者的指针,并提供一个统一的入口方法用于处理请求。抽象类通常包含:next 指针setNext 方法、以及一个纯虚方法 doHandle,后者由具体处理者实现以完成自己的业务逻辑。通过在 handle 方法内先尝试自身处理,再将请求传递给 下一处理者,实现了请求的链式传递。

#include <memory>
#include <string>
#include <iostream>struct Context {std::string request;
};class Handler {
public:virtual ~Handler() = default;void setNext(std::shared_ptr<Handler> nxt) { next = nxt; }bool handle(const Context& ctx) {if (doHandle(ctx)) return true;if (next) return next->handle(ctx);return false;}
protected:virtual bool doHandle(const Context& ctx) = 0;
private:std::shared_ptr<Handler> next;
};

在上面的代码中,Context承载请求信息,Handler 是抽象基类,setNext 负责组装链条,handle 实现“尝试处理—若失败则转发”的核心流程。具体处理者通过实现 doHandle 来完成自有逻辑,并决定是否继续传递。此设计实现了多态调用,不同处理者可以以同样的接口参与链路。

通过下述示例可以看到具体处理者如何实现自己的处理逻辑并决定链路传递:认证处理者在某些情形下直接结束请求或选择继续传递,日志处理者可以在记录后继续向下传递,最终由主处理程序完成核心任务。整体设计体现了职责分离解耦的价值。

concrete 处理者的实现要点

具体处理者实现应专注于自己的业务场景,通常需要覆盖以下要点:身份认证、权限校验、日志记录等作为示例责任,doHandle 里返回 true 表示请求已被处理,返回 false 表示继续交给下一处理者。这样的实现模式便于后续对链条进行扩展、插入新处理阶段或修改处理顺序。

在设计细节层面,可以考虑为不同处理类别提供统一的枚举或状态码,以便在链路中统一处理结果的判断逻辑,确保链路在各阶段的行为可预测、易于调试。可维护性可观测性是源码级设计的重要目标。

示例:一个简单的请求处理链

场景描述与接口定义

设定一个简单场景:请求需经过认证、日志记录,最后交由主处理执行。通过责任链,可以把这三类处理按顺序拼接在一起,且新增处理阶段不会影响现有链路的实现。关键点在于:场景化需求接口定义清晰、以及可扩展的链条组合。

下面给出一个完整的示例结构,演示如何用 C++ 实现“认证 → 日志 → 主处理”的链路,并展示如何动态组装链条。链条的灵活性来自于 setNext 方法和 handle 的统一入口。

// 与上一节的基类同包实现:
class AuthHandler : public Handler {
protected:bool doHandle(const Context& ctx) override {// 简单示例:请求等于 "authorized" 时通过认证return ctx.request == "authorized";}
};class LogHandler : public Handler {
protected:bool doHandle(const Context& ctx) override {std::cout << "Log: " << ctx.request << std::endl;// 日志记录后继续传递return false;}
};// 主处理器示例
class CoreActionHandler : public Handler {
protected:bool doHandle(const Context& ctx) override {// 最终执行核心任务std::cout << "Core action executed for: " << ctx.request << std::endl;return true;}
};

通过以上处理器,可以在运行时将它们串联成链条,并在调用处触发处理。下述代码展示了如何组装并执行链路的基本用法:

int main() {auto auth = std::make_shared();auto logger = std::make_shared<LogHandler>();auto core = std::make_shared<CoreActionHandler>();auth->setNext(logger);logger->setNext(core);Context ctx1{ "authorized" };Context ctx2{ "unauthorized" };// 成功执行链路auth->handle(ctx1);// 未授权时,链路中断,不再执行后续处理auth->handle(ctx2);return 0;
}

在这个示例中,认证处理者决定链路是否继续,日志处理者负责记录请求信息,而 核心处理者完成实际的业务操作。通过这样的结构,整个流程的 可视化与调试性明显提升,且后续只需插入新的处理阶段即可扩展功能。

广告

后端开发标签