当前位置: 首页 > news >正文

设计模式之责任链

一、责任链设计模式概念

责任链模式(Chain Of Responsibility) 是一种行为设计模式, 允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。 将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

 适用场景

  • 当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式。
  • 当必须按顺序执行多个处理者时, 可以使用该模式。
  • 如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式

责任链设计模式的结构

  1. 处理者 (Handler) 声明了所有具体处理者的通用接口。 该接口通常仅包含单个方法用于请求处理, 但有时其还会包含一个设置链上下个处理者的方法。

  2. 基础处理者 (Base Handler) 是一个可选的类, 你可以将所有处理者共用的样本代码放置在其中。

    通常情况下, 该类中定义了一个保存对于下个处理者引用的成员变量。 客户端可通过将处理者传递给上个处理者的构造函数或设定方法来创建链。 该类还可以实现默认的处理行为: 确定下个处理者存在后再将请求传递给它。

  3. 具体处理者 (Concrete Handlers) 包含处理请求的实际代码。 每个处理者接收到请求后, 都必须决定是否进行处理, 以及是否沿着链传递请求。

    处理者通常是独立且不可变的, 需要通过构造函数一次性地获得所有必要地数据。

  4. 客户端 (Client) 可根据程序逻辑一次性或者动态地生成链。 值得注意的是, 请求可发送给链上的任意一个处理者, 而非必须是第一个处理者。

代码如下:

            问题:开发一款故障报修系统,不同的业务员负责处理不同类型的故障报修,如何确保客户的维修请求能被正确处理?
            解决方案:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

#include <iostream>
#include <string>
#include <list>class BaseHandler
{
private:BaseHandler* m_nextHandler;
public:BaseHandler* setNext(BaseHandler* handler){m_nextHandler = handler;return m_nextHandler;}virtual std::string handle(std::string request){if (m_nextHandler){return m_nextHandler->handle(request);}return "";}};class RobotAI :public BaseHandler
{
public:std::string handle(std::string request) override{if (request == "使用向导"){return "RobotAI:我来处理"+request+"-。\n";}else{return BaseHandler::handle(request);}}
};class TelOperator :public BaseHandler
{
public:std::string handle(std::string request) override{if (request == "常见问题"){return "TelOperator:我来处理" + request + "-。\n";}else{return BaseHandler::handle(request);}}
};class Export :public BaseHandler
{
public:std::string handle(std::string request) override{if (request == "疑难杂症"){return "Export:我来处理" + request + "-。\n";}else{return BaseHandler::handle(request);}}
};void client(BaseHandler& handler)
{std::list<std::string> requests = {"使用向导","常见问题","常见问题","疑难杂症","gahj"};for (const std::string& request : requests){std::string result = handler.handle(request);std::cout << "Client:谁来处理" << request << std::endl;if (result.empty()){std::cout << "处理结果:无法处理请求:" << request << std::endl;}else{std::cout << "处理结果:" << result << std::endl;}}
}int main()
{RobotAI robot;TelOperator tel;Export exp;robot.setNext(&tel)->setNext(&exp);std::cout << "Chain:机器人->话务员->专家" << std::endl;client(robot);return 0;
}

 二、与其他模式的关系

  • 责任链模式 (opens new window)、 命令模式 (opens new window)、 中介者模式 (opens new window)和观察者模式 (opens new window)用于处理请求发送者和接收者之间的不同连接方式:

    • 责任链按照顺序将请求动态传递给一系列的潜在接收者, 直至其中一名接收者对请求进行处理。
    • 命令在发送者和请求者之间建立单向连接。
    • 中介者清除了发送者和请求者之间的直接连接, 强制它们通过一个中介对象进行间接沟通。
    • 观察者允许接收者动态地订阅或取消接收请求。
  • 责任链 (opens new window)通常和组合模式 (opens new window)结合使用。 在这种情况下, 叶组件接收到请求后, 可以将请求沿包含全体父组件的链一直传递至对象树的底部。

  • 责任链 (opens new window)的管理者可使用命令模式 (opens new window)实现。 在这种情况下, 你可以对由请求代表的同一个上下文对象执行许多不同的操作。

    还有另外一种实现方式, 那就是请求自身就是一个命令对象。 在这种情况下, 你可以对由一系列不同上下文连接而成的链执行相同的操作。

  • 责任链 (opens new window)和装饰模式 (opens new window)的类结构非常相似。 两者都依赖递归组合将需要执行的操作传递给一系列对象。 但是, 两者有几点重要的不同之处。

    责任链 (opens new window)的管理者可以相互独立地执行一切操作, 还可以随时停止传递请求。 另一方面, 各种装饰可以在遵循基本接口的情况下扩展对象的行为。 此外, 装饰无法中断请求的传递。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • CSS基本概念以及CSS的多种引入方式
  • CSS调整背景
  • 使用 HFD 加快 Hugging Face 模型和数据集的下载,解决443报错
  • PHP 递归遍历目录
  • 时序预测:LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较
  • 银从初级个人理财_08_第三章第二节
  • ShardingSphere 分库分表
  • 【测试项目】——个人博客系统自动化测试
  • 《微信小程序实战(3) · 推广海报制作》
  • Oracle表空间管理(二)
  • Servlet入门:服务端小程序的初试(自己学习整理的资料)
  • Spring Boot实战:使用策略模式优化商品推荐系统
  • Linux的基础知识
  • Python | Leetcode Python题解之第433题最小基因变化
  • nlohmann json:读写json文件
  • C# 免费离线人脸识别 2.0 Demo
  • CSS居中完全指南——构建CSS居中决策树
  • ES6核心特性
  • HashMap剖析之内部结构
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • Iterator 和 for...of 循环
  • Mac转Windows的拯救指南
  • React组件设计模式(一)
  • Redis在Web项目中的应用与实践
  • SQLServer插入数据
  • Sublime Text 2/3 绑定Eclipse快捷键
  • webpack项目中使用grunt监听文件变动自动打包编译
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 巧用 TypeScript (一)
  • 我与Jetbrains的这些年
  • 一些关于Rust在2019年的思考
  • 优化 Vue 项目编译文件大小
  • 你学不懂C语言,是因为不懂编写C程序的7个步骤 ...
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • #mysql 8.0 踩坑日记
  • #NOIP 2014#Day.2 T3 解方程
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • (4)事件处理——(7)简单事件(Simple events)
  • (rabbitmq的高级特性)消息可靠性
  • (超详细)语音信号处理之特征提取
  • (回溯) LeetCode 77. 组合
  • (转)Scala的“=”符号简介
  • *2 echo、printf、mkdir命令的应用
  • *setTimeout实现text输入在用户停顿时才调用事件!*
  • .net 设置默认首页
  • .NET与java的MVC模式(2):struts2核心工作流程与原理
  • ??eclipse的安装配置问题!??
  • [ C++ ] STL_list 使用及其模拟实现
  • []指针
  • [20171101]rman to destination.txt
  • [ACTF2020 新生赛]Include
  • [ARC066F]Contest with Drinks Hard
  • [AutoSar]BSW_OS 02 Autosar OS_STACK
  • [bzoj1901]: Zju2112 Dynamic Rankings
  • [C#]使用C#部署yolov8-seg的实例分割的tensorrt模型