在软件开发中,我们经常遇到需要将请求按特定顺序传递给多个处理对象的场景。比如请假审批流程中,1天内的假期由组长审批,3天内由经理审批,超过3天则需要总监批准。如果用传统的if-else嵌套实现,代码会变得难以维护:
cpp复制if (days <= 1) {
teamLeader.approve();
} else if (days <= 3) {
manager.approve();
} else {
director.approve();
}
这种实现方式存在三个明显问题:
责任链模式通过将处理对象连成一条链,让请求沿着这条链传递,直到被某个对象处理为止。这种设计带来三个核心优势:
典型应用场景包括:
责任链模式包含三个核心角色:
抽象处理者(Handler)
具体处理者(ConcreteHandler)
客户端(Client)
在C++中,我们使用抽象基类和智能指针来实现这一模式:
cpp复制class Handler {
protected:
std::shared_ptr<Handler> next;
public:
virtual ~Handler() = default;
void setNext(std::shared_ptr<Handler> handler) {
next = handler;
}
virtual void handleRequest(const Request& req) = 0;
};
具体处理者继承该基类并实现处理逻辑:
cpp复制class ConcreteHandlerA : public Handler {
public:
void handleRequest(const Request& req) override {
if (canHandle(req)) {
// 处理请求
} else if (next) {
next->handleRequest(req);
}
}
};
首先定义请假请求数据结构:
cpp复制class LeaveRequest {
public:
std::string employeeName;
int leaveDays;
std::string reason;
LeaveRequest(const std::string& name, int days, const std::string& r = "")
: employeeName(name), leaveDays(days), reason(r) {}
};
抽象基类定义处理接口和链式结构:
cpp复制class Approver : public Handler {
protected:
std::string name; // 审批人姓名
int maxDays; // 最大审批天数
public:
Approver(const std::string& n, int days)
: name(n), maxDays(days) {}
void handleRequest(const LeaveRequest& req) override {
if (req.leaveDays <= maxDays) {
approve(req);
} else if (next) {
next->handleRequest(req);
} else {
reject(req);
}
}
virtual void approve(const LeaveRequest& req) {
std::cout << name << " approved " << req.employeeName
<< "'s leave for " << req.leaveDays << " days\n";
}
virtual void reject(const LeaveRequest& req) {
std::cout << "Request for " << req.leaveDays
<< " days leave was not approved\n";
}
};
实现三个级别的审批人:
cpp复制class TeamLeader : public Approver {
public:
TeamLeader(const std::string& name)
: Approver(name, 1) {}
};
class Manager : public Approver {
public:
Manager(const std::string& name)
: Approver(name, 3) {}
};
class Director : public Approver {
public:
Director(const std::string& name)
: Approver(name, INT_MAX) {} // 总监可以审批任意天数
};
构建责任链并处理请求:
cpp复制int main() {
// 创建处理者
auto leader = std::make_shared<TeamLeader>("张组长");
auto manager = std::make_shared<Manager>("李经理");
auto director = std::make_shared<Director>("王总监");
// 构建责任链
leader->setNext(manager);
manager->setNext(director);
// 创建请假请求
LeaveRequest req1("Alice", 1, "病假");
LeaveRequest req2("Bob", 3, "年假");
LeaveRequest req3("Charlie", 5, "婚假");
// 处理请求
leader->handleRequest(req1);
leader->handleRequest(req2);
leader->handleRequest(req3);
return 0;
}
输出结果:
code复制张组长 approved Alice's leave for 1 days
李经理 approved Bob's leave for 3 days
王总监 approved Charlie's leave for 5 days
使用std::shared_ptr管理处理者对象有三大优势:
注意:在真实项目中,如果处理者的生命周期明确由某个容器管理,可以考虑使用原始指针或
std::unique_ptr来避免循环引用问题。
每个处理者的典型处理逻辑包含三个步骤:
代码模板:
cpp复制void handleRequest(const Request& req) override {
if (canHandle(req)) {
// 处理逻辑
} else if (next) {
next->handleRequest(req); // 传递请求
} else {
// 链尾处理(可选)
}
}
可以使用链式调用简化责任链的构建:
cpp复制class Handler {
public:
std::shared_ptr<Handler> setNext(std::shared_ptr<Handler> handler) {
next = handler;
return handler; // 返回新设置的处理者
}
};
// 使用方式
leader->setNext(manager)->setNext(director);
通过引入注册机制,实现运行时动态调整处理链:
cpp复制class DynamicHandler : public Handler {
std::vector<std::shared_ptr<Handler>> handlers;
public:
void addHandler(std::shared_ptr<Handler> handler) {
if (!handlers.empty()) {
handlers.back()->setNext(handler);
}
handlers.push_back(handler);
}
void handleRequest(const Request& req) override {
if (!handlers.empty()) {
handlers.front()->handleRequest(req);
}
}
};
有时需要在处理后中断传递链:
cpp复制void handleRequest(const Request& req) override {
if (canHandle(req)) {
if (process(req)) {
return; // 处理成功则中断
}
}
if (next) next->handleRequest(req);
}
当请求被处理后通知相关对象:
cpp复制class ObservableHandler : public Handler {
std::vector<std::function<void()>> observers;
public:
void addObserver(std::function<void()> obs) {
observers.push_back(obs);
}
void handleRequest(const Request& req) override {
if (canHandle(req)) {
process(req);
notifyObservers();
} else if (next) {
next->handleRequest(req);
}
}
void notifyObservers() {
for (auto& obs : observers) {
obs();
}
}
};
循环引用:处理者相互引用导致内存泄漏
std::weak_ptr或明确生命周期管理请求丢失:所有处理者都无法处理请求
顺序依赖:处理顺序影响结果
相似点:
不同点:
将责任链中的每个处理者实现为命令对象:
cpp复制class CommandHandler : public Handler {
Command command;
public:
void handleRequest(const Request& req) override {
if (canHandle(req)) {
command.execute(req);
} else if (next) {
next->handleRequest(req);
}
}
};
相似点:
不同点:
日志系统:不同级别日志由不同处理器处理
cpp复制logger->setNext(warningLogger)->setNext(errorLogger);
输入验证:多层验证链
cpp复制validator->setNext(formatChecker)->setNext(businessRuleChecker);
游戏开发:事件处理系统
cpp复制uiHandler->setNext(gameLogicHandler)->setNext(physicsHandler);
Web中间件:请求处理管道
cpp复制authMiddleware->setNext(logMiddleware)->setNext(routeMiddleware);
在实现时需要注意:
cpp复制auto handler = std::make_shared<LambdaHandler>(
[](const Request& req) {
// 处理逻辑
return canHandle;
}
);
cpp复制template<typename... Handlers>
std::shared_ptr<Handler> makeChain(Handlers... handlers) {
auto chain = std::make_shared<HandlerChain>();
(chain->addHandler(handlers), ...);
return chain;
}
cpp复制class FunctionHandler {
std::function<bool(const Request&)> handler;
std::shared_ptr<FunctionHandler> next;
public:
void handle(const Request& req) {
if (!handler(req) && next) {
next->handle(req);
}
}
};
经过完整实现和分析,可以得出以下责任链模式的最佳实践:
在C++实现中特别要注意:
典型的反模式包括:
最后需要强调的是,责任链模式虽然强大,但不应过度使用。它最适合以下场景:
在实际项目中,我通常会先评估需求的复杂度,对于简单的固定流程,直接使用函数调用可能更合适;对于复杂的、可能变化的处理流程,责任链模式能显著提高代码的灵活性和可维护性。