设计模式每日硬核训练 Day 16:责任链模式(Chain of Responsibility Pattern)完整讲解与实战应用
🔄 回顾 Day 15:享元模式小结
在 Day 15 中,我们学习了享元模式(Flyweight Pattern):
- 通过共享对象,分离内部状态与外部状态,大量减少内存开销。
- 适用于字符渲染、游戏场景、图标缓存等高频对象复用场景。
今天的主角是极具灵活性的责任链模式(Chain of Responsibility Pattern)。
责任链模式:将请求沿着处理链传递,节点动态决定是否处理请求或传递给下一个节点,构建解耦、灵活的处理流程。
一、责任链模式的核心动机
在系统中,常常需要多个对象处理同一个请求,但又希望:
- 谁处理由运行时决定
- 发送者不需要知道具体哪个对象处理了请求
✅ 应用场景:
- 日志处理链:Debug → Info → Error
- GUI 事件传递:子控件未处理,则父控件继续处理
- 中间件框架:权限验证、日志记录、异常捕获
二、结构图(UML)
+----------------+
| Handler |
+----------------+
| +setNext() |
| +handle() |
+----------------+/\/ \
+-----------------+ +-----------------+
| ConcreteHandlerA | | ConcreteHandlerB |
+-----------------+ +-----------------+
三、角色说明
角色 | 职责描述 |
---|---|
Handler | 抽象处理者接口,定义 setNext 和 handle 方法 |
ConcreteHandler | 具体处理者,决定自己处理或传递给下一个节点 |
四、C++ 实现:日志处理责任链
✅ 抽象处理器
class Logger {
protected:std::shared_ptr<Logger> next_;public:void setNext(std::shared_ptr<Logger> next) {next_ = next;}virtual void logMessage(int level, const std::string& message) = 0;virtual ~Logger() = default;
};
✅ 具体处理器(不同级别)
class DebugLogger : public Logger {
public:void logMessage(int level, const std::string& message) override {if (level == 1)std::cout << "[DEBUG] " << message << std::endl;else if (next_)next_->logMessage(level, message);}
};class InfoLogger : public Logger {
public:void logMessage(int level, const std::string& message) override {if (level == 2)std::cout << "[INFO] " << message << std::endl;else if (next_)next_->logMessage(level, message);}
};class ErrorLogger : public Logger {
public:void logMessage(int level, const std::string& message) override {if (level == 3)std::cout << "[ERROR] " << message << std::endl;else if (next_)next_->logMessage(level, message);}
};
✅ 使用示例
int main() {auto debugLogger = std::make_shared<DebugLogger>();auto infoLogger = std::make_shared<InfoLogger>();auto errorLogger = std::make_shared<ErrorLogger>();debugLogger->setNext(infoLogger);infoLogger->setNext(errorLogger);auto loggerChain = debugLogger;loggerChain->logMessage(1, "调试信息");loggerChain->logMessage(2, "普通信息");loggerChain->logMessage(3, "错误信息");return 0;
}
输出:
[DEBUG] 调试信息
[INFO] 普通信息
[ERROR] 错误信息
五、责任链常见应用场景总结
场景 | 链式责任节点 |
---|---|
GUI 事件处理 | 子控件 → 父控件 → 窗口根 |
Web 请求处理 | 认证中间件 → 日志中间件 → 缓存中间件 |
业务审批流 | 组长 → 部门经理 → 总经理 |
客户请求分发 | 客户端路由规则链 |
配置查找链 | 环境变量 → 配置文件 → 默认值 |
六、优点与缺点分析
✅ 优点:
- 请求发送者与处理者解耦
- 责任链可动态组合,支持灵活扩展
- 便于增加、修改处理节点逻辑
❗ 缺点:
- 可能导致请求未被任何节点处理(需要合理设计)
- 调试复杂,请求流向不易跟踪
七、责任链与其他模式对比
模式 | 核心意图 | 是否处理一件事 |
---|---|---|
责任链 Chain | 请求沿链传递,节点决定处理与否 | ❓(可能处理/可能不处理) |
观察者 Observer | 所有订阅者都收到通知 | ✅(全部处理) |
命令模式 Command | 将请求封装成对象,单点发送 | ✅(单一处理者) |
八、面试回答模板
“我们在 Web 框架中使用责任链模式构建中间件处理流。每个中间件负责一部分功能,比如鉴权、日志、缓存,如果某个中间件未处理,就将请求传递给下一个。责任链极大提升了模块解耦和扩展性,同时支持动态组合不同处理顺序。”
✅ 建议强调链式流动、模块化处理、动态组合优势。
九、口诀记忆
“节点串成链,请求顺流传;能处就拦截,不能就后延。”
十、明日预告:Day 17
中介者模式(Mediator Pattern):统一控制对象交互,减少对象间耦合,简化系统复杂度。