C++设计模式——Chain of Responsibility职责链模式

news/2024/9/17 7:12:06/ 标签: 设计模式, 责任链模式, c++, 开发语言, c语言

一,职责链模式的定义

职责链模式,又被称为责任链模式,是一种行为型设计模式,它让多个对象依次处理收到的请求,直到处理完成为止。

职责链模式需要使用多个对象,其中的每个对象要么处理请求,要么将请求传递给下一个对象,该模式因此可以实现发送方与接收方的松散耦合。

在职责链模式中,一个对象可以被理解为处理器,每个处理器都包含对下一个处理器的引用,多个对象之间形成了一个链表的结构。

职责链模式在现实生活中的抽象实例:

审批流程:在流程中,当一个申请需要多级审批时,可以使用职责链模式。每一级审批者都是职责链的一部分。

银行账户验证:在银行系统中,需要对用户进行身份验证和授权操作,而验证操作涉及多个步骤。

异常处理:在程序开发中,每个异常处理器可以处理特定类型的异常,如果当前处理器无法解决,则传递给下一个处理器。

二,职责链模式的结构

职责链模式主要包含以下组件:

1.抽象处理器(Handler):

处理器的抽象类,声明处理请求的抽象接口,并持有对下一个处理器的引用。

2.具体处理器(ConcreteHandler):

继承自抽象处理器,包含了对处理请求接口的具体实现,负责处理特定类型的请求或将请求传递给下一个处理器。

3.客户端(Client):

负责创建处理器的实例,并将它们加入到职责链中。然后向第一个处理器发送请求,并等待职责链的返回结果。

组件之间的工作步骤如下:

1.客户端将请求传递给职责链中的第一个处理器。

2.第一个处理器尝试处理请求。如果处理成功,则结束处理过程并返回结果,如果无法处理,则将请求转发给下一个处理器。

3.下一个处理器重复步骤2,直到找到能够处理请求的处理器,或者职责链中没有更多的处理器。

4.客户端获得处理结果。

对应UML类图:

三,职责链模式代码样例

#include <iostream>
#include <string>
class Handler
{
protected:Handler* successor;
public:void setSuccessor(Handler* successor){this->successor = successor;}virtual void handleRequest(const std::string& request) = 0;
};
class ConcreteHandler1 : public Handler
{
public:void handleRequest(const std::string& request) override{if (request == "Type1"){std::cout << "Handling request of type Type1." << std::endl;}else if (successor != nullptr){successor->handleRequest(request);}else{std::cout << "Unable to handle the request." << std::endl;}}
};
class ConcreteHandler2 : public Handler
{
public:void handleRequest(const std::string& request) override{if (request == "Type2"){std::cout << "Handling request of type Type2." << std::endl;}else if (successor != nullptr){successor->handleRequest(request);}else{std::cout << "Unable to handle the request." << std::endl;}}
};
class ConcreteHandler3 : public Handler
{
public:void handleRequest(const std::string& request) override{if (request == "Type3"){std::cout << "Handling request of type Type3." << std::endl;}else if (successor != nullptr){successor->handleRequest(request);}else{std::cout << "Unable to handle the request." << std::endl;}}
};
int main()
{Handler* handler1 = new ConcreteHandler1();Handler* handler2 = new ConcreteHandler2();Handler* handler3 = new ConcreteHandler3();handler1->setSuccessor(handler2);handler2->setSuccessor(handler3);handler1->handleRequest("Type2");handler1->handleRequest("Type3");handler1->handleRequest("Type4");delete handler1;delete handler2;delete handler3;return 0;
}

运行结果:

Handling request of type Type2.
Handling request of type Type3.
Unable to handle the request.

四,职责链模式的应用场景

命令处理器:比如在游戏或GUI应用中,用户可以发送各种操作命令,如“播放音乐”、“关闭窗口”,而具体执行过程由一系列处理器完成。

日志记录器:将不同严重等级的日志交给不同的处理器去打印。

Web服务开发:在Web服务中,对请求进行校验和过滤,如权限验证、数据校验等。

权限控制:在用户权限管理中,可以根据角色的不同职责分配不同的权限验证步骤。

消息路由:在网络通信中,将不同类型的消息分别发送给不同的处理程序。

五,职责链模式的优缺点

职责链模式的优点:

和命令模式类似,可以实现发送者和接收者的解耦。

灵活性强,可以修改职责链中的结构和顺序。

有扩展性,可以在最小改动的情况下添加新的处理器。

处理器可以在不同的职责链中重复使用。

职责链模式的缺点:

对请求的处理可能覆盖不全,导致bug的产生。

请求的处理过程十分冗长。

请求的传递涉及多个对象,性能开销大。

责任链需要被一直维护和管理。

六,代码实战

Demo1:日志记录器

#include <iostream>
#include <string>
#include <vector>
//Logger接口
class Logger {
public:virtual void log(const std::string& message) = 0;
};
//处理正常日志
class InfoLogger: public Logger{
public:void log(const std::string& message) override {std::cerr << "Info: " << message << std::endl;}
};
//处理调试日志
class DebugLogger: public Logger{
public:void log(const std::string& message) override {std::cout << "Debug: " << message << std::endl;}
};
//处理错误日志
class ErrorLogger: public Logger{
public:void log(const std::string& message) override {std::cerr << "Error: " << message << std::endl;}
};
class LoggingChain {
private:std::vector<std::shared_ptr<Logger>> loggers;
public:void addLogger(std::shared_ptr<Logger> logger) {loggers.push_back(logger);}void log(const std::string& message) {for (auto it = loggers.rbegin(); it != loggers.rend(); ++it) {(*it)->log(message);}}
};
int main() {LoggingChain chain;chain.addLogger(std::make_shared<InfoLogger>());chain.addLogger(std::make_shared<DebugLogger>());chain.addLogger(std::make_shared<ErrorLogger>());chain.log("This is a test message.");return 0;
}

运行结果:

Error: This is a test message.
Debug: This is a test message.
Info: This is a test message.

Demo2:模拟消息接收

#include <iostream>
#include <string>
#include <vector>
class Message {
public:virtual ~Message() {}
};
class TextMessage : public Message {
};
class ImageMessage : public Message {
};
class MessageHandler{
public:virtual void handle(Message* msg) = 0;
};
class TextProcessor: public MessageHandler{
public:void handle(Message* msg) override{if (dynamic_cast<TextMessage*>(msg)) {std::cout << "handling a text message." << std::endl;process(*static_cast<TextMessage*>(msg));}else {forward(msg);}}
private:void process(TextMessage& msg) {}void forward(Message* msg) {}
};
class ImageProcessor: public MessageHandler{
public:void handle(Message* msg) override {if (dynamic_cast<ImageMessage*>(msg)) {std::cout << "handling an image message." << std::endl;process(*static_cast<ImageMessage*>(msg));}else {forward(msg);}}
private:void process(ImageMessage& img){}void forward(Message* msg){}
};
class ChainOfResponsibility {
public:void setHandler(MessageHandler* handler){current_ = handler;}void handle(Message* msg) {current_->handle(msg);}
private:MessageHandler* current_ = nullptr;
};
int main() {ChainOfResponsibility chain;TextProcessor txtProc;ImageProcessor imgProc;chain.setHandler(&txtProc);chain.handle(new TextMessage());chain.setHandler(&imgProc);chain.handle(new ImageMessage());return 0;
}

运行结果:

handling a text message.
handling an image message.

七,参考阅读

https://www.geeksforgeeks.org/chain-responsibility-design-pattern/

https://www.tutorialspoint.com/design_pattern/chain_of_responsibility_pattern.htm

https://sourcemaking.com/design_patterns/chain_of_responsibility


http://www.ppmy.cn/news/1522588.html

相关文章

iPhone手机清理软件:照片清理功能全解析

在数字化生活中&#xff0c;智能手机成为我们记录生活点滴的主要工具&#xff0c;尤其是iPhone&#xff0c;以其卓越的相机功能备受用户青睐。然而&#xff0c;成千上万的照片迅速堆积&#xff0c;不仅占用了大量存储空间&#xff0c;还使得设备运行缓慢。在众多解决方案中&…

数据传输安全——混合加解密(国密)

国密SM2与SM4混合加密解密工具类详解及其与其他加密算法的对比分析 在当今互联网时代,信息安全变得尤为重要。随着国家密码局发布的商用密码算法(即国密算法)逐渐普及,SM2和SM4等算法因其高效性和安全性成为了国内应用中的重要组成部分。本文不仅将详细介绍一个基于Java的…

如何本地搭建Whisper语音识别模型

要在本地搭建Whisper语音识别模型&#xff0c;你需要遵循以下步骤&#xff0c;注意Whisper模型是由OpenAI发布的&#xff0c;但基于你的要求&#xff0c;这里将尽可能提供详细的指导&#xff1a; 环境准备&#xff1a; 首先&#xff0c;确保你的计算机安装了Python&#xff0c;…

SAM2POINT:以zero-shot且快速的方式将任何 3D 视频分割为视频

摘要 我们介绍 SAM2POINT&#xff0c;这是一种采用 Segment Anything Model 2 (SAM 2) 进行零样本和快速 3D 分割的初步探索。 SAM2POINT 将任何 3D 数据解释为一系列多向视频&#xff0c;并利用 SAM 2 进行 3D 空间分割&#xff0c;无需进一步训练或 2D-3D 投影。 我们的框架…

Mac(M2)系统手动安装ADB

ADB压缩包下载地址 下载解压后运行命令 zsh命令 // /Desktop/android为解压后文件夹的路径 ~ 符号表示跟目录1. echo export PATH$PATH:~/Desktop/android/platform-tools/ >> ~/.zshrc// 使第一步配置生效 2. source ~/.zshrc shell命令 // /Desktop/android为解…

计算机组成原理:总线技术深度解析

目录 1. 总线技术概述 1.1 什么是总线&#xff1f; 1.2 总线的基本功能 2. 总线的类型 2.1 内部总线 2.2 外部总线 3. 总线的标准与协议 3.1 常见的总线标准 3.2 总线协议 4. 总线的性能考量 4.1 带宽 4.2 延迟 4.3 可扩展性 5. 总线的未来趋势 6. 结语 在计算机…

VMware中共享文件夹没了怎么办?

1.进入root su root 需要提前设置密码 sudo passwd root 2.创建一个hgfs文件夹&#xff0c;share就在这里面 sudo mkdir /mnt/hgfs/ 3.输入下面的命令 sudo mount -t fuse.vmhgfs-fuse .host:/ /mnt/hgfs -o allow_other 4.然后就能找到share文件夹了&#xff0c;注意每…

PDF读取表格写入EXCEL

声明&#xff1a;只记录&#xff0c;不推荐&#xff0c;因为e-iceblue的spire.pdf是收费的&#xff0c;要licence。 pom引入 <repositories><repository><id>com.e-iceblue</id><name>e-iceblue</name><url>https://repo.e-iceblu…

《云原生安全攻防》-- K8s攻击案例:高权限Service Account接管集群

《网安面试指南》http://mp.weixin.qq.com/s?__bizMzkwNjY1Mzc0Nw&mid2247484339&idx1&sn356300f169de74e7a778b04bfbbbd0ab&chksmc0e47aeff793f3f9a5f7abcfa57695e8944e52bca2de2c7a3eb1aecb3c1e6b9cb6abe509d51f&scene21#wechat_redirect 在本节课程中…

奥威让您更懂现金流情况

企业现金流一旦出了问题都是大问题&#xff0c;会直接影响到企业的日常运作&#xff0c;甚至直接关系到企业能不能继续存活&#xff0c;因此现金流量表是企业财务分析中重要报表之一&#xff0c;也是企业监控财务监控情况的重要手段之一。那么这么重要的一份现金流量表该怎么做…

数据库管理-第238期 23ai:全球分布式数据库-架构与组件(20240904)

数据库管理238期 2024-09-04 数据库管理-第238期 23ai&#xff1a;全球分布式数据库-架构与组件&#xff08;20240904&#xff09;1 架构图2 分片数据库与分片3 Shard Catalog4 Shard Director5 Global Service6 管理界面总结 数据库管理-第238期 23ai&#xff1a;全球分布式数…

RT-Thread 使用HTTP固件下载方式进行OTA远程升级

参考资料:RT-T官网资料如下链接所示 STM32通用Bootloader (rt-thread.org) 1.app程序env配置过程 参考上述资料中"制作 app 固件"章节&#xff0c;分区大小根据自己设备而定&#xff0c;以下是我以407VET6为例设置的fal分区 notes:上述分区是由片内flash(on-chip)…

科研绘图系列:R语言差异基因四分图(Quad plot)

文章目录 介绍加载R包导入数据数据预处理画图参考介绍 四分图(Quad plot)是一种数据可视化技术,通常用于展示四个变量之间的关系。它由四个子图组成,每个子图都显示两个变量之间的关系。四分图的布局通常是2x2的网格,每个格子代表一个变量对的散点图。 在四分图中,通常…

2024数学建模国赛选题建议+团队助攻资料(已更新完毕)

目录 一、题目特点和选题建议 二、模型选择 1、评价模型 2、预测模型 3、分类模型 4、优化模型 5、统计分析模型 三、white学长团队助攻资料 1、助攻代码 2、成品论文PDF版 3、成品论文word版 9月5日晚18&#xff1a;00就要公布题目了&#xff0c;根据历年竞赛题目…

clickhouse-v24.1-离线部署

部署版本 数据库版本&#xff1a;24.1.1.2048 jdk版本&#xff1a;jdk8 4个文件&#xff08;三个ck的包&#xff09;&#xff1a; OpenJDK8U-jdk_x64_linux_hotspot_8u382b05.tar clickhouse-client-24.1.1.2048.x86_64.rpm clickhouse-common-static-24.1.1.2048.x86_64.…

Unity之获取Avpro视频画面并在本地创建缩略图

一、效果 获取StreamingAssets文件夹下的所有视频&#xff08;包含其子文件夹&#xff09;&#xff0c;获取指定时间的视频画面&#xff0c;然后将图片保存到本地磁盘中。 二、关于Avpro的事件监听 当指定视频时间进度时会触发FinishedSeeking&#xff0c;代表加载完成这时我们…

muduo 网络库学习项目引入 Boost 依赖

文章目录 下载 [Boost 源码库](https://www.boost.org/)编译通过 CMake 引入 Boost 项目Boost 链接库指引文档的问题 muduo 这个项目比较老旧了&#xff0c;但是仍然是学习网络库实现的一个不错的参考&#xff0c;所以还是得看看书自己动手实践一下。 没想到跟着书上的代码练手…

2024国赛数学建模备赛|30种常用的算法模型之最优算法-非线性规划

1.1 非线性规划的实例与定义 如果目标函数或约束条件中包含非线性函数&#xff0c;就称这种规划问题为非线性规划问题。一般说来&#xff0c;解非线性规划要比解线性规划问题困难得多。而且&#xff0c;也不象线性规划有 单纯形法这一通用方法&#xff0c;非线性规划目前还没…

SpringBoot3+Vue3开发商店上货管理系统

系统介绍 上货管理系统是专门为各种类型商店打造的一款进货管理系统。针对整个商店进货流程&#xff0c;提供很多方便功能&#xff0c;帮助店家完成上货流程。比如上货清单管理功能、上货清单确认功能、供货商管理功能、商品管理功能等。 技术栈 后端&#xff1a;SpringBoot…

Spark MLlib模型训练—回归算法 Factorization Machines Regression

Spark MLlib模型训练—回归算法 Factorization Machines Regression 在大数据与机器学习领域,推荐系统、广告点击率预测以及评分预测等应用场景中,经常涉及到高度稀疏的特征数据,这对传统的回归模型提出了挑战。因子分解机(Factorization Machines, FMs)是一种广泛应用于…