1. 职责链模式基础回顾与C++实现要点
在C++中实现职责链模式,首先要理解其核心思想:将请求的发送者和接收者解耦,让多个对象都有机会处理这个请求。这些处理对象被连接成一条链,请求沿着链传递直到被处理或到达链尾。
典型的职责链模式包含三个关键组件:
- Handler接口:定义处理请求的接口和设置后继者的方法
- ConcreteHandler:具体处理者实现处理逻辑,决定是否处理请求或传递给后继者
- Client:创建处理链并向链头发送请求
C++实现时需要注意几个特殊点:
- 内存管理:如果使用原始指针构建链,需要明确所有权关系。现代C++更推荐使用智能指针
- 性能考量:链式调用会带来一定的性能开销,在性能敏感场景需要评估
- 异常安全:确保处理过程中异常不会导致资源泄漏或链断裂
cpp复制// 现代C++风格的职责链实现示例
class Handler {
public:
virtual ~Handler() = default;
virtual std::shared_ptr<Handler> setNext(std::shared_ptr<Handler> handler) = 0;
virtual void handleRequest(const std::string& request) = 0;
};
class BaseHandler : public Handler {
protected:
std::shared_ptr<Handler> next_;
public:
std::shared_ptr<Handler> setNext(std::shared_ptr<Handler> handler) override {
next_ = handler;
return handler;
}
void handleRequest(const std::string& request) override {
if(next_) {
next_->handleRequest(request);
}
}
};
2. 高级应用场景与实现技巧
2.1 动态链重构
在实际项目中,处理链可能需要根据运行时条件动态调整。我们可以引入ChainManager类来管理链的构建和重组:
cpp复制class ChainManager {
std::shared_ptr<Handler> chainHead_;
std::unordered_map<std::string, std::shared_ptr<Handler>> handlers_;
public:
void registerHandler(const std::string& id, std::shared_ptr<Handler> handler) {
handlers_[id] = handler;
}
void buildChain(const std::vector<std::string>& order) {
if(order.empty()) return;
chainHead_ = handlers_[order[0]];
auto current = chainHead_;
for(size_t i = 1; i < order.size(); ++i) {
current->setNext(handlers_[order[i]]);
current = handlers_[order[i]];
}
}
void processRequest(const std::string& request) {
if(chainHead_) {
chainHead_->handleRequest(request);
}
}
};
2.2 优先级中断机制
标准职责链一旦某个处理者接手请求,流程就会终止。但在某些场景下,我们可能需要允许多个处理者按优先级处理同一请求:
cpp复制class PriorityHandler : public BaseHandler {
int priority_;
public:
PriorityHandler(int priority) : priority_(priority) {}
void handleRequest(const std::string& request) override {
if(canHandle(request)) {
// 处理请求
process(request);
// 根据优先级决定是否继续传递
if(shouldContinue(request)) {
BaseHandler::handleRequest(request);
}
} else {
BaseHandler::handleRequest(request);
}
}
// ...其他实现细节
};
2.3 异步职责链
在处理IO密集型任务时,同步的链式调用会导致性能瓶颈。我们可以实现异步版本的职责链:
cpp复制class AsyncHandler : public Handler {
std::shared_ptr<Handler> next_;
std::thread::id workerThread_;
public:
void handleRequest(const std::string& request) override {
std::async(std::launch::async, [this, request] {
workerThread_ = std::this_thread::get_id();
if(canHandle(request)) {
process(request);
} else if(next_) {
next_->handleRequest(request);
}
});
}
// ...其他实现
};
3. 性能优化与线程安全
3.1 缓存优化策略
频繁创建的职责链会导致性能问题,可以采用对象池模式缓存处理者实例:
cpp复制class HandlerPool {
std::map<std::type_index, std::vector<std::shared_ptr<Handler>>> pool_;
public:
template<typename T>
std::shared_ptr<T> acquire() {
static_assert(std::is_base_of<Handler, T>::value,
"T must inherit from Handler");
auto& handlers = pool_[typeid(T)];
if(handlers.empty()) {
return std::make_shared<T>();
}
auto handler = std::dynamic_pointer_cast<T>(handlers.back());
handlers.pop_back();
return handler;
}
template<typename T>
void release(std::shared_ptr<T> handler) {
pool_[typeid(T)].push_back(handler);
}
};
3.2 线程安全实现
多线程环境下使用职责链需要特别注意线程安全问题:
cpp复制class ThreadSafeHandler : public BaseHandler {
mutable std::mutex mtx_;
public:
std::shared_ptr<Handler> setNext(std::shared_ptr<Handler> handler) override {
std::lock_guard<std::mutex> lock(mtx_);
return BaseHandler::setNext(handler);
}
void handleRequest(const std::string& request) override {
std::shared_ptr<Handler> next;
{
std::lock_guard<std::mutex> lock(mtx_);
next = next_;
}
if(next) {
next->handleRequest(request);
}
}
};
4. 实际工程案例解析
4.1 网络请求处理管道
在网络框架中,职责链模式常用于构建请求处理管道。以下是一个简化实现:
cpp复制class HttpHandler : public BaseHandler {
public:
void handleRequest(const HttpRequest& request) override {
if(request.path == "/api/user") {
// 处理用户API请求
processUserRequest(request);
} else {
BaseHandler::handleRequest(request);
}
}
};
class AuthMiddleware : public BaseHandler {
public:
void handleRequest(const HttpRequest& request) override {
if(!validateToken(request.token)) {
sendErrorResponse(401, "Unauthorized");
return;
}
BaseHandler::handleRequest(request);
}
};
// 构建处理链
auto chain = std::make_shared<AuthMiddleware>();
chain->setNext(std::make_shared<RateLimiter>())
->setNext(std::make_shared<HttpHandler>());
4.2 游戏事件系统
游戏开发中常用职责链处理输入事件:
cpp复制class InputHandler : public BaseHandler {
public:
void handleEvent(const InputEvent& event) override {
if(event.type == EventType::KeyPress &&
event.key == Key::Space) {
// 处理空格键按下
handleJump();
} else {
BaseHandler::handleEvent(event);
}
}
};
// 构建输入处理链
auto inputChain = std::make_shared<UIInputHandler>();
inputChain->setNext(std::make_shared<PlayerInputHandler>())
->setNext(std::make_shared<DebugInputHandler>());
5. 模式变体与扩展应用
5.1 责任树模式
将线性链扩展为树形结构,实现更复杂的处理逻辑:
cpp复制class BranchHandler : public Handler {
std::vector<std::shared_ptr<Handler>> branches_;
public:
void addBranch(std::shared_ptr<Handler> handler) {
branches_.push_back(handler);
}
void handleRequest(const Request& req) override {
for(auto& branch : branches_) {
if(branch->canHandle(req)) {
branch->handleRequest(req);
break;
}
}
}
};
5.2 过滤器链模式
结合职责链和过滤器模式,实现请求/响应的双向处理:
cpp复制class Filter {
public:
virtual void doFilter(Request& req, Response& res, FilterChain& chain) = 0;
};
class FilterChain {
std::vector<std::shared_ptr<Filter>> filters_;
size_t index_ = 0;
public:
void addFilter(std::shared_ptr<Filter> filter) {
filters_.push_back(filter);
}
void doFilter(Request& req, Response& res) {
if(index_ < filters_.size()) {
auto& filter = filters_[index_++];
filter->doFilter(req, res, *this);
}
}
};
6. 测试与调试技巧
6.1 单元测试策略
测试职责链时需要关注链的完整性和每个处理者的行为:
cpp复制TEST(ChainOfResponsibility, BasicFlow) {
auto handler1 = std::make_shared<MockHandler>();
auto handler2 = std::make_shared<MockHandler>();
handler1->setNext(handler2);
// 测试handler1能处理的请求
EXPECT_CALL(*handler1, canHandle("test1")).WillOnce(Return(true));
EXPECT_CALL(*handler1, process("test1")).Times(1);
EXPECT_CALL(*handler2, process(_)).Times(0);
handler1->handleRequest("test1");
// 测试请求传递到handler2
EXPECT_CALL(*handler1, canHandle("test2")).WillOnce(Return(false));
EXPECT_CALL(*handler2, canHandle("test2")).WillOnce(Return(true));
EXPECT_CALL(*handler2, process("test2")).Times(1);
handler1->handleRequest("test2");
}
6.2 调试与日志记录
为职责链添加详细的日志记录有助于调试:
cpp复制class LoggingHandler : public BaseHandler {
public:
void handleRequest(const std::string& request) override {
log("Handling request: " + request);
auto start = std::chrono::steady_clock::now();
BaseHandler::handleRequest(request);
auto end = std::chrono::steady_clock::now();
log("Request handled in " +
std::to_string(
std::chrono::duration_cast<std::chrono::milliseconds>(
end - start).count()) + "ms");
}
};
7. 性能对比与模式选择
职责链模式并非适用于所有场景,下表对比了不同场景下的适用性:
| 场景特征 | 适合使用职责链 | 不适合使用职责链 |
|---|---|---|
| 处理者数量多且可能变化 | ✓ | |
| 请求需要动态路由 | ✓ | |
| 处理顺序固定不变 | ✓ | |
| 性能要求极其严格 | ✓ | |
| 需要明确的处理结果 | ✓ |
在实际项目中,我通常会考虑以下因素决定是否使用职责链模式:
- 系统是否需要动态调整处理流程
- 处理者的数量和类型是否经常变化
- 性能要求是否允许额外的间接调用开销
- 是否需要保持处理者之间的松耦合
8. 与其他模式的协同应用
职责链模式常与其他设计模式结合使用,形成更强大的解决方案:
8.1 与命令模式结合
cpp复制class CommandHandler : public BaseHandler {
std::map<std::string, std::unique_ptr<Command>> commands_;
public:
void registerCommand(const std::string& name, std::unique_ptr<Command> cmd) {
commands_[name] = std::move(cmd);
}
void handleRequest(const std::string& request) override {
auto parts = split(request);
if(commands_.count(parts[0])) {
commands_[parts[0]]->execute(parts);
return;
}
BaseHandler::handleRequest(request);
}
};
8.2 与观察者模式结合
cpp复制class ObservableHandler : public BaseHandler, public Observable {
public:
void handleRequest(const std::string& request) override {
notifyObservers(RequestStarted, request);
try {
BaseHandler::handleRequest(request);
notifyObservers(RequestCompleted, request);
} catch(...) {
notifyObservers(RequestFailed, request);
throw;
}
}
};
9. 现代C++特性应用
C++17/20的新特性可以让职责链实现更加优雅:
9.1 使用std::variant处理多类型请求
cpp复制using Request = std::variant<HttpRequest, FileRequest, RpcRequest>;
class VariantHandler {
public:
virtual void handle(const Request& req) = 0;
};
class MultiHandler : public VariantHandler {
public:
void handle(const Request& req) override {
std::visit([](auto&& arg) {
using T = std::decay_t<decltype(arg)>;
if constexpr(std::is_same_v<T, HttpRequest>) {
// 处理HTTP请求
} else if constexpr(std::is_same_v<T, FileRequest>) {
// 处理文件请求
}
}, req);
}
};
9.2 协程实现异步链
C++20协程可以简化异步职责链的实现:
cpp复制task<void> CoroutineHandler::handleRequest(const Request& req) {
if(canHandle(req)) {
co_await processAsync(req);
} else if(next_) {
co_await next_->handleRequest(req);
}
}
10. 反模式与常见误区
在实践中,我发现有几个常见的误区和反模式值得警惕:
-
无限循环链:没有正确设置链尾,导致请求无限循环
- 解决方案:在基类中实现默认的链尾行为
-
性能黑洞:链过长且每个处理者都进行耗时操作
- 解决方案:引入超时机制或异步处理
-
状态污染:处理者意外修改了请求状态,影响后续处理
- 解决方案:使用不可变请求或深度拷贝
-
调试困难:链式调用导致调用栈过深
- 解决方案:添加请求ID和详细日志
-
链构建错误:错误的链顺序导致业务逻辑错误
- 解决方案:使用专门的Builder类管理链构建
cpp复制// 链构建器示例
class ChainBuilder {
std::shared_ptr<Handler> head_;
std::shared_ptr<Handler> tail_;
public:
template<typename T, typename... Args>
ChainBuilder& add(Args&&... args) {
auto handler = std::make_shared<T>(std::forward<Args>(args)...);
if(!head_) {
head_ = handler;
tail_ = handler;
} else {
tail_->setNext(handler);
tail_ = handler;
}
return *this;
}
std::shared_ptr<Handler> build() {
return head_;
}
};
// 使用示例
auto chain = ChainBuilder()
.add<AuthHandler>(config)
.add<LoggingHandler>(logger)
.add<BusinessHandler>()
.build();
