新谈设计模式 Chapter 13 — 责任链模式 Chain of Responsibility
2026/4/15 13:47:22 网站建设 项目流程

Chapter 13 — 责任链模式 Chain of Responsibility

灵魂速记:踢皮球——一个处理不了,就传给下一个,直到有人接手。


秒懂类比

你在公司报销:

  1. 金额 ≤ 500 →组长直接批
  2. 500 < 金额 ≤ 5000 → 组长签不了,传给经理
  3. 5000 < 金额 ≤ 50000 → 经理签不了,传给总监
  4. 金额 > 50000 → 总监签不了,传给CEO

每一级要么自己处理,要么传给上级。请求沿着链一直走,直到有人能处理。


问题引入

// 灾难现场:一堆 if-else 嵌套voidhandleRequest(Request&req){if(req.type=="spam"){// 过滤垃圾邮件}elseif(req.type=="auth"){// 检查认证}elseif(req.type=="rateLimit"){// 限流}elseif(req.type=="logging"){// 日志}// 每加一种处理,改这个函数……// 处理顺序硬编码,无法灵活调整}

模式结构

┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ Handler A │───→│ Handler B │───→│ Handler C │───→│ null │ │ (组长) │ │ (经理) │ │ (总监) │ │ (链尾) │ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │ │ │ 能处理? 能处理? 能处理? ├─是→处理完毕 ├─是→处理完毕 ├─是→处理完毕 └─否→传下去 └─否→传下去 └─否→无人处理

C++ 实现

#include<iostream>#include<memory>#include<string>// ========== 处理者基类 ==========classApprover{public:virtual~Approver()=default;std::shared_ptr<Approver>setNext(std::shared_ptr<Approver>next){next_=next;returnnext;// 返回下一个处理者,支持链式设置}voidhandle(conststd::string&applicant,doubleamount){if(canApprove(amount)){approve(applicant,amount);}elseif(next_){std::cout<<" "<<name()<<": ¥"<<amount<<" 超出我的权限,往上报\n";next_->handle(applicant,amount);}else{std::cout<<" ❌ 没人能批准 "<<applicant<<" 的 ¥"<<amount<<" 报销\n";}}protected:virtualboolcanApprove(doubleamount)const=0;virtualstd::stringname()const=0;voidapprove(conststd::string&applicant,doubleamount){std::cout<<" ✅ "<<name()<<" 批准了 "<<applicant<<" 的 ¥"<<amount<<" 报销\n";}private:std::shared_ptr<Approver>next_;};// ========== 具体处理者 ==========classTeamLead:publicApprover{protected:boolcanApprove(doubleamount)constoverride{returnamount<=500;}std::stringname()constoverride{return"组长";}};classManager:publicApprover{protected:boolcanApprove(doubleamount)constoverride{returnamount<=5000;}std::stringname()constoverride{return"经理";}};classDirector:publicApprover{protected:boolcanApprove(doubleamount)constoverride{returnamount<=50000;}std::stringname()constoverride{return"总监";}};classCEO:publicApprover{protected:boolcanApprove(doubleamount)constoverride{returnamount<=500000;}std::stringname()constoverride{return"CEO";}};intmain(){// 组装责任链autoceo=std::make_shared<CEO>();autodirector=std::make_shared<Director>();automanager=std::make_shared<Manager>();autolead=std::make_shared<TeamLead>();lead->setNext(manager)->setNext(director)->setNext(ceo);// 提交报销std::cout<<"=== 报销 ¥200 ===\n";lead->handle("张三",200);std::cout<<"\n=== 报销 ¥3000 ===\n";lead->handle("李四",3000);std::cout<<"\n=== 报销 ¥30000 ===\n";lead->handle("王五",30000);std::cout<<"\n=== 报销 ¥800000 ===\n";lead->handle("赵六",800000);}

输出:

=== 报销 ¥200 === ✅ 组长 批准了 张三 的 ¥200 报销 === 报销 ¥3000 === 组长: ¥3000 超出我的权限,往上报 ✅ 经理 批准了 李四 的 ¥3000 报销 === 报销 ¥30000 === 组长: ¥30000 超出我的权限,往上报 经理: ¥30000 超出我的权限,往上报 ✅ 总监 批准了 王五 的 ¥30000 报销 === 报销 ¥800000 === 组长: ¥800000 超出我的权限,往上报 经理: ¥800000 超出我的权限,往上报 总监: ¥800000 超出我的权限,往上报 CEO: ¥800000 超出我的权限,往上报 ❌ 没人能批准 赵六 的 ¥800000 报销

另一种用法:中间件管道

责任链不只是"找人处理",还可以是"每个人都处理一部分"(像流水线):

classMiddleware{public:virtual~Middleware()=default;std::shared_ptr<Middleware>linkWith(std::shared_ptr<Middleware>next){next_=next;returnnext;// 返回下一个中间件,支持链式设置}boolcheck(conststd::string&request){if(!doCheck(request))returnfalse;// 自己拦截了if(next_)returnnext_->check(request);// 传给下一个returntrue;// 全部通过}protected:virtualbooldoCheck(conststd::string&request)=0;private:std::shared_ptr<Middleware>next_;};

Web 框架中的中间件(认证 → 限流 → 日志 → 业务逻辑)就是这种模式。


什么时候用?

✅ 适合❌ 别用
多个对象都可能处理请求只有一个处理者
处理者和顺序需要运行时灵活调整处理逻辑固定不变
不希望发送者知道谁会处理发送者必须知道处理者
中间件/过滤器管道所有处理者都必须执行

防混淆

责任链 vs 装饰器

责任链装饰器
结构都是链式都是链式
传递可以中断(有人处理了就停)不中断(每层都执行)
目的找到能处理的人层层增强功能

一句话分清:责任链可以停,装饰器必须走完。

责任链 vs Command

责任链Command
请求去向沿链传递,不确定谁处理直接发给指定的接收者
处理者数量多个候选一个确定的

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询