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

一,职责链模式的定义

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

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

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

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

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

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

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

二,职责链模式的结构

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

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.rhkb.cn/news/416849.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构——归并排序

目录 引言 归并排序 1.算法思想 2.算法步骤 3.代码实现 4.复杂度分析 5.算法优化 (1)区间优化 (2)判断区间是否有序 6.非递归实现 7.应用场景 结束语 引言 在学习完 数据结构——快速排序 后&#xff0c;我们接着学习一种高效的排序方法——归并排序 求点赞收藏关…

stm32之外部flash下载算法

文章目录 下载算法下载到芯片的核心思想算法程序中擦除操作执行流程擦除操作大致流程&#xff1a;算法程序中编程操作执行流程算法程序中校验操作执行流程 创建MDK下载算法通用流程第1步&#xff0c;使用MDK提供好的程序模板第2步&#xff0c;修改工程名第3步&#xff0c;修改使…

值得听歌入手的开放式耳机推荐?分享四款开放式蓝牙耳机

作为网易云十级的耳机重度患者来说&#xff0c;我觉得值得听歌入手的开放式耳机还得是挂耳式的开放式耳机。 因为挂耳式的开放式耳机拥有着不错的佩戴体验&#xff0c;挂耳式的设计还能够牢牢贴合耳廓&#xff0c;而且不用入耳&#xff0c;所以能够保持耳道空气流通&#xff0…

【软件测试】软件测试-----什么是Bug?Bug是如何分级的?Bug的生命周期是怎样的?如何描述一个Bug?

博客目录 一.软件测试的生命周期二.BUG的定义和级别2.1 bug的概念.2.2 如何描述一个bug.2.3bug的级别2.3.1 bug分级的意义.2.3.2 bug的四种级别. 三.BUG的生命周期.四.当与开发人员发生冲突该如何处理(高频面试)五.总结 一.软件测试的生命周期 软件测试贯穿于软件的整个生命周…

出现 TypeError: Cannot read properties of undefined (reading ‘getUserMedia‘) 解决方法

目录 1. 问题所示2. 原理分析3. 解决方法1. 问题所示 调用摄像头的时候出现如下所示: Uncauht (in promise) TypeError: Cannot read properties of undefined (reading getUserMedia)截图如下: 2. 原理分析 TypeError: Cannot read properties of undefined (reading ‘…

NSS题目练习

[SWPUCTF 2022 新生赛]js_sign 打开后先随便填入&#xff0c;点击check&#xff0c;发现出现弹窗&#xff0c;并且尝试抓包抓不到&#xff0c;说明是js前端 查看源码找到js文件 补充&#xff1a; ‌‌ btoa函数是‌JavaScript中的一个全局函数&#xff0c;用于将二进制字符串…

【分享】Excel表格设置“打开密码”的两种方法

在工作中&#xff0c;Excel文件通常包含敏感数据&#xff0c;出于安全性考虑&#xff0c;给文件设置打开密码是非常有效的方式。接下来&#xff0c;小编给大家介绍两种方法&#xff0c;帮助你轻松为Excel文件设置密码。 方法一&#xff1a;在Excel表里设置“打开密码” 这是Ex…

基于yolov8的水面垃圾水面漂浮物检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv8的水面垃圾与漂浮物检测系统是一种高效、智能的监测解决方案。该系统利用YOLOv8这一前沿的深度学习模型&#xff0c;结合智能视频分析技术&#xff0c;对河道、湖泊等水面的垃圾漂浮物进行实时监测与识别。 YOLOv8作为YOLO系列的最新迭代&#xff0c;…

828华为云征文|华为云Flexus云服务器X实例部署Cockpit服务

828华为云征文&#xff5c;华为云Flexus云服务器X实例部署Cockpit笔记工具 前言一、Flexus云服务器X实例介绍1.1 Flexus云服务器X实例简介1.2 Flexus云服务器X实例特点1.3 Flexus云服务器X实例使用场景 二、Cockpit介绍2.1 Cockpit简介2.2 Cockpit特点 三、本次实践介绍3.1 本次…

录屏软件电脑,精选5款录屏神器推荐

嘿&#xff0c;朋友们&#xff01;想象一下&#xff0c;你正在与好友分享你最新的游戏成就&#xff0c;或是与同事展示你的最新项目进展&#xff0c;但却发现文字描述无法完美呈现你的精彩瞬间。别担心&#xff0c;在这个数字化的时代&#xff0c;我们有着无数种方式记录和分享…

计算机网络(一) —— 网络基础入门

目录 一&#xff0c;关于网络 二&#xff0c;协议 2.1 协议是什么&#xff0c;有什么用&#xff1f; 2.2 协议标准谁定的&#xff1f; 2.3 协议分层 2.4 OSI 七层模型 2.5 TCP/IP 四层模型 三&#xff0c;网络传输基本流程 3.1 局域网中两台主机通信* 3.2 报文的封装与…

Hadoop运行jps没有datanode节点【已解决】

1 原因&#xff1a; 格式化NameNode后&#xff0c;如果DataNode的clusterID与新的NameNode的clusterID不匹配&#xff0c;DataNode将无法加入集群&#xff0c;导致HDFS无法正常提供服务。 2 解决方式&#xff1a; 将新的NameNode的clusterID与DataNode的clusterID保持一致 &…

TCP/IP网络编程:Linux实现的web服务器

请求消息&#xff08;Request Message&#xff09; 的结构 这是客户端向服务端发送的请求消息的结构&#xff0c;Web服务器需要解析并响应客户端请求&#xff0c;从图中看出&#xff0c;请求信息包含请求行&#xff0c;消息头&#xff0c;消息体等三个部分&#xff0c;这里我们…

计算机网络 第1章 概述

文章目录 计算机网络概念计算机网络的组成计算机网络的功能三种数据交换技术电路交换&#xff08;Circuit Switching&#xff09;报文交换&#xff08;message&#xff09;分组交换 三种交换方式性能对比计算机网络的分类计算机网络的性能指标性能指标1&#xff1a;速率性能指标…

重磅!微信放开公众号注册限制!只要手机号,不用实名!

重磅&#xff01;微信放开公众号注册限制&#xff01;只要手机号&#xff0c;不用实名&#xff01; 随着移动互联网的发展&#xff0c;微信公众号已经成为了许多个人与企业传递信息、分享内容的首选平台。就在近日&#xff0c;微信官方再次放出大招&#xff1a;公众号注册无需…

Seataf分布式事务的使用

一、事务的四大特征&#xff08;面试题&#xff09; 原子性&#xff1a;一个事务是不可分割的&#xff0c;要不都做&#xff0c;要不都不做一致性&#xff1a;事务必须是使数据库从一个一致性变成另一个一致性状态隔离性&#xff1a;一个事务的执行不被其他事务干扰&#xff0…

开放式耳机对耳朵伤害大吗?开放式耳机值不值得购买?

开放式耳机对耳朵的伤害相对较小。这是因为开放式耳机通常不需要将耳塞插入耳道&#xff0c;因此不会对耳道造成物理压力&#xff0c;也不会因为耳塞堵塞耳道而增加耳内压力&#xff0c;减少了使用耳机时可能对耳膜和耳道造成的损伤风险。同时&#xff0c;由于开放式耳机不会完…

前端请求的路径baseURL怎么来的 ?nodejs解决cors问题的一种方法

背景&#xff1a;后端使用node.js搭建&#xff0c;用的是express 前端请求的路径baseURL怎么来的 &#xff1f; 前后端都在同一台电脑上运行&#xff0c;后端的域名就是localhost&#xff0c;如果使用的是http协议&#xff0c;后端监听的端口号为3000&#xff0c;那么前端请求…

欧科云链OKLink受邀参与WebX ,旗下EaaS助力项目方“弯道超车”

8 月 27 日&#xff0c;作为亚洲顶级区块链行业盛会 WebX 的 side event 之一的 OKJ Night 在东京盛大拉开帷幕&#xff0c;会上正式宣布 OKCoin Japan 升级为 OKJ&#xff0c;进一步以合规的形式推动区块链产业在日蓬勃发展。日本首相为本次活动发来贺电。 OKLink 非常荣幸作为…

Java学习中如何分辨 = 和 == 及其使用方法

在学习Java编程语言时&#xff0c; 和 是两个非常基础的运算符&#xff0c;虽然它们看起来相似&#xff0c;但在语义和应用场景上却有明显的区别。理解并正确使用这两个符号对于编写正确且高效的Java代码至关重要。 1. 运算符&#xff1a;赋值运算符 在Java中是赋值运算符&a…