责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它通过将请求的发送者和接收者解耦,使多个对象都有机会处理这个请求。这些处理对象被连接成一条链,请求沿着这条链传递,直到有一个对象处理它为止。
责任链模式的核心在于构建一条处理链,每个处理节点都有机会处理请求,但也可以选择将请求传递给链中的下一个节点。这种设计带来了几个显著优势:
提示:责任链模式特别适合处理那些需要多级审批、分层次处理或存在多种可能处理方式的场景。
一个标准的责任链模式通常包含以下角色:
在C++实现中,通常会使用抽象基类定义Handler接口,然后通过指针或引用连接各个处理者形成链条。
让我们先看一个最基础的责任链模式C++实现框架:
cpp复制#include <iostream>
using namespace std;
// 请求类型枚举
enum RequestType {
LEAVE, // 请假
RAISE, // 加薪
QUIT // 离职
};
// 抽象处理者
class AbstractManager {
protected:
AbstractManager* _next; // 后继处理者
public:
virtual void handleRequest(RequestType rt) = 0;
void setNext(AbstractManager* am) { _next = am; }
virtual ~AbstractManager() {} // 虚析构函数
};
// 具体处理者:直属领导
class DirectLeader : public AbstractManager {
public:
void handleRequest(RequestType rt) override {
if (rt == LEAVE) {
cout << "直属领导批准了请假申请" << endl;
}
else if (_next != nullptr) {
cout << "直属领导无权处理,转交给上级..." << endl;
_next->handleRequest(rt);
}
else {
cout << "请求未被任何处理者处理" << endl;
}
}
};
// 具体处理者:部门经理
class DepartmentManager : public AbstractManager {
public:
void handleRequest(RequestType rt) override {
if (rt == RAISE) {
cout << "部门经理批准了加薪申请" << endl;
}
else if (_next != nullptr) {
cout << "部门经理无权处理,转交给上级..." << endl;
_next->handleRequest(rt);
}
else {
cout << "请求未被任何处理者处理" << endl;
}
}
};
// 具体处理者:总经理
class GeneralManager : public AbstractManager {
public:
void handleRequest(RequestType rt) override {
if (rt == QUIT) {
cout << "总经理处理了离职申请" << endl;
}
else if (_next != nullptr) {
cout << "总经理无权处理,转交给上级..." << endl;
_next->handleRequest(rt);
}
else {
cout << "请求未被任何处理者处理" << endl;
}
}
};
构建处理链并使用的典型方式如下:
cpp复制int main() {
// 创建处理者实例
DirectLeader* leader = new DirectLeader();
DepartmentManager* manager = new DepartmentManager();
GeneralManager* gm = new GeneralManager();
// 构建责任链
leader->setNext(manager);
manager->setNext(gm);
// 创建请求
RequestType requests[] = {LEAVE, RAISE, QUIT, LEAVE};
// 处理请求
for (auto req : requests) {
cout << "\n处理新请求:" << req << endl;
leader->handleRequest(req);
}
// 释放资源
delete leader;
delete manager;
delete gm;
return 0;
}
在这个例子中,我们清晰地看到请求如何沿着责任链传递,直到找到合适的处理者。每个处理者只关注自己能处理的请求类型,对于无法处理的请求则自动转发给下一个处理者。
假设我们要为一个公司开发OA(办公自动化)系统,其中审批流程需要满足以下要求:
这些需求正是责任链模式的典型应用场景。让我们设计一个更完善的审批系统。
首先定义更详细的请求类型和审批级别:
cpp复制// 更详细的请求类型
enum OARequestType {
LEAVE_1DAY, // 1天以内请假
LEAVE_3DAY, // 3天以内请假
LEAVE_7DAY, // 7天以内请假
LEAVE_LONG, // 长期请假
EXPENSE_500, // 500元以内报销
EXPENSE_2000, // 2000元以内报销
EXPENSE_5000, // 5000元以内报销
EXPENSE_LARGE, // 大额报销
PURCHASE_SMALL, // 小额采购
PURCHASE_LARGE // 大额采购
};
// 审批级别
enum ApproveLevel {
LEVEL_TEAM_LEADER, // 组长
LEVEL_DEPT_MANAGER, // 部门经理
LEVEL_DIVISION_HEAD,// 事业部总监
LEVEL_CFO, // 财务总监
LEVEL_CEO // 首席执行官
};
然后实现具体的审批处理器:
cpp复制class Approver {
protected:
Approver* _next;
string _name;
ApproveLevel _level;
public:
Approver(const string& name, ApproveLevel level)
: _name(name), _level(level), _next(nullptr) {}
virtual void processRequest(OARequestType req) = 0;
void setNext(Approver* next) {
_next = next;
}
virtual ~Approver() {}
};
class TeamLeader : public Approver {
public:
TeamLeader(const string& name) : Approver(name, LEVEL_TEAM_LEADER) {}
void processRequest(OARequestType req) override {
if (req == LEAVE_1DAY || req == EXPENSE_500) {
cout << _name << "(组长)批准了申请类型:" << req << endl;
}
else if (_next != nullptr) {
cout << _name << "(组长)无权审批,转交上级..." << endl;
_next->processRequest(req);
}
else {
cout << "申请类型 " << req << " 未被任何审批人处理" << endl;
}
}
};
// 其他审批人类似实现...
class DeptManager : public Approver {
public:
DeptManager(const string& name) : Approver(name, LEVEL_DEPT_MANAGER) {}
void processRequest(OARequestType req) override {
if (req == LEAVE_3DAY || req == EXPENSE_2000 || req == PURCHASE_SMALL) {
cout << _name << "(部门经理)批准了申请类型:" << req << endl;
}
else if (_next != nullptr) {
cout << _name << "(部门经理)无权审批,转交上级..." << endl;
_next->processRequest(req);
}
else {
cout << "申请类型 " << req << " 未被任何审批人处理" << endl;
}
}
};
在实际系统中,审批链可能会根据组织架构动态变化:
cpp复制class ApprovalSystem {
private:
Approver* _chainHead;
unordered_map<ApproveLevel, Approver*> _approvers;
public:
ApprovalSystem() : _chainHead(nullptr) {}
void addApprover(Approver* approver) {
_approvers[approver->_level] = approver;
rebuildChain();
}
void removeApprover(ApproveLevel level) {
_approvers.erase(level);
rebuildChain();
}
void processRequest(OARequestType req) {
if (_chainHead != nullptr) {
_chainHead->processRequest(req);
}
else {
cout << "当前没有可用的审批人" << endl;
}
}
private:
void rebuildChain() {
if (_approvers.empty()) {
_chainHead = nullptr;
return;
}
// 按审批级别排序
vector<ApproveLevel> levels;
for (auto& pair : _approvers) {
levels.push_back(pair.first);
}
sort(levels.begin(), levels.end());
// 重建责任链
Approver* prev = nullptr;
for (auto level : levels) {
Approver* current = _approvers[level];
if (prev == nullptr) {
_chainHead = current;
}
else {
prev->setNext(current);
}
prev = current;
}
if (prev != nullptr) {
prev->setNext(nullptr);
}
}
};
这种实现方式允许我们在运行时动态添加或移除审批人,系统会自动重建责任链,保证了系统的灵活性。
在实际开发中,我们经常会根据具体需求对经典责任链模式进行一些调整:
例如,实现一个可以修改请求内容的变体:
cpp复制class ModifiableRequest {
public:
int value;
string description;
bool isApproved;
ModifiableRequest(int v, const string& desc)
: value(v), description(desc), isApproved(false) {}
};
class ValueHandler {
protected:
ValueHandler* _next;
public:
virtual void handleRequest(ModifiableRequest& req) = 0;
void setNext(ValueHandler* next) { _next = next; }
virtual ~ValueHandler() {}
};
class DiscountHandler : public ValueHandler {
public:
void handleRequest(ModifiableRequest& req) override {
if (req.value > 1000 && !req.isApproved) {
req.value = static_cast<int>(req.value * 0.9);
cout << "应用了10%折扣,新价格:" << req.value << endl;
}
if (_next != nullptr) {
_next->handleRequest(req);
}
}
};
class ApprovalHandler : public ValueHandler {
public:
void handleRequest(ModifiableRequest& req) override {
if (req.value <= 500) {
req.isApproved = true;
cout << "申请已批准" << endl;
}
if (_next != nullptr) {
_next->handleRequest(req);
}
}
};
当责任链较长或处理请求较频繁时,我们需要考虑性能优化:
例如,实现一个带缓存的责任链:
cpp复制class CachedHandler {
protected:
CachedHandler* _next;
unordered_set<OARequestType> _supportedTypes;
public:
virtual void processRequest(OARequestType req) = 0;
void setNext(CachedHandler* next) { _next = next; }
void addSupportedType(OARequestType type) {
_supportedTypes.insert(type);
}
bool canHandle(OARequestType req) const {
return _supportedTypes.count(req) > 0;
}
virtual ~CachedHandler() {}
};
class SmartDeptManager : public CachedHandler {
public:
SmartDeptManager(const string& name) {
addSupportedType(LEAVE_3DAY);
addSupportedType(EXPENSE_2000);
addSupportedType(PURCHASE_SMALL);
}
void processRequest(OARequestType req) override {
if (canHandle(req)) {
cout << "部门经理处理了申请类型:" << req << endl;
}
else if (_next != nullptr) {
_next->processRequest(req);
}
else {
cout << "申请类型 " << req << " 未被处理" << endl;
}
}
};
与装饰器模式比较:
与命令模式比较:
与状态模式比较:
在实际项目中使用责任链模式时,需要注意以下几点:
一个健壮的责任链实现应该包含完善的错误处理:
cpp复制class RobustHandler {
protected:
RobustHandler* _next;
public:
virtual bool handleRequest(const Request& req, Response& resp) = 0;
void setNext(RobustHandler* next) {
if (next == this) throw logic_error("不能设置自己为下一个处理者");
_next = next;
}
bool passToNext(const Request& req, Response& resp) {
if (_next != nullptr) {
return _next->handleRequest(req, resp);
}
resp.setError("没有处理者能够处理该请求");
return false;
}
virtual ~RobustHandler() {}
};
为责任链模式编写测试时,应重点考虑以下方面:
例如,使用Google Test框架编写测试用例:
cpp复制TEST(ChainOfResponsibilityTest, SingleHandlerApproves) {
TeamLeader leader("张组长");
Request req(LEAVE_1DAY);
Response resp;
EXPECT_TRUE(leader.handleRequest(req, resp));
EXPECT_EQ(resp.getApprover(), "张组长");
}
TEST(ChainOfResponsibilityTest, RequestPassesThroughChain) {
TeamLeader leader("张组长");
DeptManager manager("李经理");
leader.setNext(&manager);
Request req(EXPENSE_2000);
Response resp;
EXPECT_TRUE(leader.handleRequest(req, resp));
EXPECT_EQ(resp.getApprover(), "李经理");
}
TEST(ChainOfResponsibilityTest, UnhandledRequest) {
TeamLeader leader("张组长");
Request req(PURCHASE_LARGE);
Response resp;
EXPECT_FALSE(leader.handleRequest(req, resp));
EXPECT_EQ(resp.getError(), "没有处理者能够处理该请求");
}
在实际项目中使用责任链模式多年,我总结了一些宝贵的经验教训:
明确处理边界:每个处理者的职责范围应该清晰明确,避免重叠或遗漏。曾经在一个电商项目中,因为两个处理者的审批范围有重叠,导致某些订单被重复处理。
谨慎处理链顺序:处理链的顺序往往会影响系统行为。有一次我们将风险检查放在链的最后面,结果导致无效请求通过了前面的所有检查,浪费了大量资源。
考虑添加监控点:在关键处理节点添加监控和日志,可以帮助快速定位问题。我们曾经实现过一个可视化工具,可以实时显示请求在责任链中的流动情况,极大提高了调试效率。
避免过度使用:不是所有多步骤处理都适合用责任链模式。对于流程固定、步骤简单的场景,使用责任链反而会增加复杂度。一般当处理流程需要动态变化或扩展时,才考虑使用责任链模式。
性能热点:在高并发场景下,责任链可能成为性能瓶颈。我们曾经通过将处理链无状态化并使用对象池优化,将吞吐量提高了3倍。
测试覆盖:确保测试用例覆盖所有可能的处理路径,包括请求被链中每个处理者处理的情况,以及请求未被任何处理者处理的情况。
与其它模式组合:责任链模式常与模板方法、工厂方法等模式结合使用。例如,可以使用工厂方法创建处理链,用模板方法定义处理流程的骨架。
cpp复制// 结合工厂方法创建处理链的例子
class HandlerFactory {
public:
static Approver* createApprovalChain() {
Approver* leader = new TeamLeader("组长");
Approver* manager = new DeptManager("经理");
Approver* director = new DivisionHead("总监");
leader->setNext(manager);
manager->setNext(director);
return leader;
}
};
责任链模式是一种强大的设计模式,正确使用可以大幅提高代码的灵活性和可维护性。但它也不是银弹,需要根据具体场景谨慎使用。在实际项目中,我通常会先考虑更简单的解决方案,只有当需求明确需要动态、灵活的处理流程时,才会引入责任链模式。