1. 职责链模式概述
职责链模式(Chain of Responsibility)是一种行为型设计模式,它允许你将请求沿着处理者链进行传递,直到有一个处理者能够处理它为止。这种模式的核心思想是将多个处理者对象连接成一条链,请求沿着这条链传递,每个处理者决定是否处理该请求以及是否将请求传递给链中的下一个处理者。
在实际开发中,职责链模式特别适用于以下场景:
- 有多个对象可以处理同一个请求,但具体由哪个对象处理需要在运行时动态决定
- 需要在不明确指定接收者的情况下,向多个对象中的一个提交请求
- 可动态指定一组对象处理请求
提示:职责链模式与链表结构有相似之处,但职责链强调的是处理逻辑的传递而非单纯的数据结构
2. 模式结构与核心组件
2.1 基本类结构
职责链模式通常包含以下几个关键组件:
-
Handler(抽象处理者):
- 定义处理请求的接口
- 通常包含一个指向后继者的引用
- 可以实现后继者链的默认行为
-
ConcreteHandler(具体处理者):
- 实现处理请求的具体逻辑
- 能够访问后继者
- 如果能够处理请求则处理,否则将请求转发给后继者
-
Client(客户端):
- 创建处理链
- 向链头的具体处理者对象提交请求
2.2 典型实现方式
在C++中,职责链模式的典型实现如下:
cpp复制// 抽象处理者
class Handler {
public:
virtual ~Handler() {}
void setSuccessor(Handler* successor) {
m_successor = successor;
}
virtual void handleRequest(int request) = 0;
protected:
Handler* m_successor = nullptr;
};
// 具体处理者A
class ConcreteHandlerA : public Handler {
public:
void handleRequest(int request) override {
if (request < 10) {
// 处理请求
} else if (m_successor) {
// 转发请求
m_successor->handleRequest(request);
}
}
};
// 具体处理者B
class ConcreteHandlerB : public Handler {
public:
void handleRequest(int request) override {
if (request >= 10 && request < 20) {
// 处理请求
} else if (m_successor) {
// 转发请求
m_successor->handleRequest(request);
}
}
};
3. 模式实现详解
3.1 基础实现分析
让我们深入分析示例代码中的实现细节:
handle.h 头文件解析:
cpp复制#ifndef __HANDLE_H_
#define __HANDLE_H_
class handle {
public:
virtual ~handle();
virtual void handle_request() = 0; // 纯虚函数,强制子类实现
void set_successor(handle* succ); // 设置后继者
handle* get_successor(); // 获取后继者
protected:
handle(); // 保护构造函数
handle(handle* succ); // 带后继者的构造函数
private:
handle* _succ; // 后继者指针
};
关键点说明:
- 抽象基类
handle定义了处理请求的接口handle_request() - 通过
_succ指针维护链式结构 - 构造函数设为protected,防止直接实例化抽象类
3.2 具体处理者实现
concrete_handle_a.cpp 关键部分:
cpp复制void concrete_handle_a::handle_request() {
if(this->get_successor() != 0) {
cout << "concrete_handle_a 我把处理权给后继节点......" << endl;
this->get_successor()->handle_request();
} else {
cout << "concrete_handle_a 没有后继了,我必须自己处理......" << endl;
}
}
行为分析:
- 首先检查是否有后继者
- 如果有后继者,将请求传递给后继者
- 如果没有后继者,则必须自己处理(示例中只是输出信息)
3.3 客户端使用方式
main.cpp 客户端代码:
cpp复制int main(int argc, char* argv[]) {
handle* h1 = new concrete_handle_a();
handle* h2 = new concrete_handle_b();
h1->set_successor(h2); // 建立链式关系
h1->handle_request(); // 触发处理流程
return 0;
}
执行流程:
- 创建两个具体处理者对象
- 设置h1的后继者为h2
- 调用h1的handle_request()方法启动处理流程
4. 模式优势与应用场景
4.1 主要优势
-
降低耦合度:
- 请求发送者不需要知道具体由哪个对象处理请求
- 处理者之间也不需要知道彼此的具体细节
-
动态性:
- 可以在运行时动态改变链中的处理者顺序或新增/删除处理者
- 比静态的条件判断语句更灵活
-
责任单一:
- 每个处理者只需关注自己负责的部分
- 符合单一职责原则
4.2 典型应用场景
-
多级审批系统:
- 如请假审批流程(组长→经理→总监)
- 每个审批者只处理自己权限范围内的请求
-
异常处理机制:
- 如try-catch块形成的异常处理链
- 每个catch块处理特定类型的异常
-
事件处理系统:
- GUI事件传播(控件→父容器→窗口)
- 每个组件决定是否处理事件或继续传递
-
日志记录系统:
- 日志信息可以传递给多个记录器(控制台、文件、网络等)
- 每个记录器决定是否记录该日志
5. 实现注意事项与最佳实践
5.1 实现细节考量
-
后继者设置方式:
- 可以在构造函数中设置
- 也可以通过专门的方法动态设置
- 示例中使用了
set_successor()方法
-
请求传递控制:
- 处理者可以决定完全处理请求后不再传递
- 也可以部分处理后继续传递
- 示例中是简单的全有或全无策略
-
链的终止条件:
- 必须有明确的终止条件防止无限循环
- 示例中通过
_succ是否为nullptr判断
5.2 性能优化建议
-
避免过长的处理链:
- 链过长会影响性能
- 可以考虑设置最大传递深度
-
缓存处理结果:
- 对于相同请求可以缓存处理结果
- 避免重复处理的开销
-
异步处理:
- 对于耗时操作可以考虑异步处理
- 不影响主流程的执行
5.3 常见问题解决方案
问题1:请求未被任何处理者处理
- 解决方案:可以在链尾添加一个默认处理者,确保所有请求都能被处理
问题2:循环引用导致内存泄漏
- 解决方案:使用智能指针管理处理者对象的生命周期
问题3:处理顺序错误
- 解决方案:严格测试链的构建顺序,可以添加链验证方法
6. 扩展与变体
6.1 带中断的职责链
允许处理者在处理请求后决定是否继续传递请求:
cpp复制void handle_request() override {
bool handled = do_handle(); // 尝试处理
if (!handled && m_successor) {
m_successor->handle_request();
}
}
6.2 功能链模式
每个处理者都对请求进行部分处理,然后传递给下一个处理者:
cpp复制void handle_request(Request& req) override {
process_part(req); // 处理部分
if (m_successor) {
m_successor->handle_request(req);
}
}
6.3 组合模式与职责链结合
处理者本身可以是组合模式中的组合对象,形成树形处理结构:
cpp复制class CompositeHandler : public Handler {
public:
void add(Handler* handler) { /*...*/ }
void handle_request() override {
for (auto h : m_children) {
h->handle_request();
if (request_handled) break;
}
}
private:
std::vector<Handler*> m_children;
};
7. 与其他模式的关系
-
与命令模式:
- 职责链模式中的请求通常封装为命令对象
- 命令模式关注请求的封装,职责链关注请求的传递
-
与组合模式:
- 可以结合使用形成树形处理结构
- 组合模式描述部分-整体层次结构
-
与装饰器模式:
- 都基于递归组合
- 装饰器模式添加功能,职责链模式处理请求
-
与观察者模式:
- 都是解耦发送者和接收者
- 观察者模式是一对多,职责链模式是链式传递
在实际项目中,职责链模式经常与其他模式结合使用,以构建更灵活的系统架构。理解这些模式之间的关系有助于我们在设计时做出更合适的选择。