第一次接触责任链模式是在处理一个多层审批系统时。当时系统需要根据报销金额自动路由到不同级别的审批人,从部门主管到财务总监再到CEO。如果硬编码这些判断逻辑,每次审批规则变化都需要重新编译代码——这显然不是优雅的解决方案。责任链模式(Chain of Responsibility)正是为解决这类"请求的发送者和接收者解耦"的问题而生。
在面向对象设计中,责任链属于行为型模式,其核心思想是:让多个对象都有机会处理请求,从而避免请求发送者与接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有对象处理它为止。就像现实中的申诉流程,你的问题会从基层员工开始逐级上报,直到找到有权限处理的层级。
典型应用场景包括:
用C++实现标准的责任链模式,主要包含以下角色:
code复制┌─────────────┐ ┌──────────────────┐
│ Handler │<>───│ ConcreteHandler │
├─────────────┤ ├──────────────────┤
│ +SetNext() │ │ +HandleRequest() │
│ +Handle() │ └──────────────────┘
└─────────────┘
Handler基类是所有处理者的公共接口,通常定义为抽象类:
cpp复制class Handler {
public:
virtual ~Handler() = default;
void SetNext(Handler* next) {
next_ = next;
}
virtual void HandleRequest(int request) const {
if (next_) {
next_->HandleRequest(request);
}
}
protected:
Handler* next_ = nullptr; // 后继处理者指针
};
ConcreteHandler是具体处理者,需要重写HandleRequest方法:
cpp复制class Manager : public Handler {
public:
explicit Manager(int limit) : limit_(limit) {}
void HandleRequest(int request) const override {
if (request <= limit_) {
std::cout << "Manager approves: " << request << "\n";
} else {
Handler::HandleRequest(request); // 传递给上级
}
}
private:
int limit_;
};
我们实现一个完整的报销审批流程:
cpp复制class Director : public Handler {
public:
explicit Director(int limit) : limit_(limit) {}
void HandleRequest(int request) const override {
if (request <= limit_) {
std::cout << "Director approves: " << request << "\n";
} else {
Handler::HandleRequest(request);
}
}
private:
int limit_;
};
class CEO : public Handler {
public:
void HandleRequest(int request) const override {
std::cout << "CEO approves: " << request << "\n";
}
};
构建处理链并测试不同金额的审批:
cpp复制int main() {
Manager manager(1000); // 经理审批≤1000
Director director(5000); // 总监审批≤5000
CEO ceo; // CEO无限制
manager.SetNext(&director);
director.SetNext(&ceo);
// 测试不同金额
manager.HandleRequest(800); // Manager审批
manager.HandleRequest(3500); // Director审批
manager.HandleRequest(10000); // CEO审批
return 0;
}
责任链的优势在于运行时可以动态调整处理流程:
cpp复制// 临时增加审计环节
class Auditor : public Handler {
public:
void HandleRequest(int request) const override {
std::cout << "[Audit] Recording request: " << request << "\n";
Handler::HandleRequest(request);
}
};
// 客户端调整链
Auditor auditor;
auditor.SetNext(&manager); // 插入审计节点
某些场景下需要中断链传递(如登录验证失败):
cpp复制void HandleRequest(int request) const override {
if (!CheckPermission()) {
std::cout << "Access denied!\n";
return; // 不再传递
}
Handler::HandleRequest(request);
}
推荐使用智能指针避免内存泄漏:
cpp复制class Handler {
protected:
std::shared_ptr<Handler> next_;
public:
void SetNext(std::shared_ptr<Handler> next) {
next_ = next;
}
// ...其他成员...
};
// 客户端使用
auto manager = std::make_shared<Manager>(1000);
auto director = std::make_shared<Director>(5000);
manager->SetNext(director);
循环引用:当处理者相互引用时会导致链成环
请求丢失:未正确处理链末尾情况
cpp复制void HandleRequest(int request) const override {
if (CanHandle(request)) {
// ...处理逻辑...
} else if (next_) {
next_->HandleRequest(request);
} else {
std::cerr << "Unhandled request: " << request << "\n";
}
}
性能热点:长链导致的遍历开销
拦截过滤器模式:在Web框架中常见,允许在链上插入多个过滤器:
cpp复制class Filter {
public:
virtual bool DoFilter(HttpRequest& req) = 0;
virtual ~Filter() = default;
};
class FilterChain {
public:
void AddFilter(Filter* filter) {
filters_.push_back(filter);
}
bool Execute(HttpRequest& req) {
for (auto filter : filters_) {
if (!filter->DoFilter(req)) return false;
}
return true;
}
private:
std::vector<Filter*> filters_;
};
适合使用责任链的场景:
不适用的情况:
在实际项目中,我常将责任链与工厂模式结合,通过配置文件动态构建处理链。例如在游戏开发中,不同伤害类型(物理、魔法、真实伤害)对应不同的伤害计算链,通过JSON配置即可调整伤害计算流程,无需重新编译代码。