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

C++软件设计模式之责任链模式

责任链模式的动机与意图

动机:
在软件开发中,经常会遇到需要处理一系列请求或事件的情况。这些请求可能需要经过多个处理对象,每个对象根据其职责决定是否处理请求或将其传递给下一个对象。责任链模式(Chain of Responsibility Pattern)提供了一种将请求的发送者和接收者解耦的方式,允许多个对象都有机会处理请求,从而避免了请求发送者与接收者之间的紧密耦合。

意图:
责任链模式的意图是使多个对象都有机会处理请求,从而避免请求的发送者与接收者之间的耦合。将这些对象连成一条链,并沿着这条链传递请求,直到有对象处理它为止。

适用场合

  1. 多个对象可以处理同一请求,但具体由哪个对象处理在运行时确定。
  2. 需要在不明确指定接收者的情况下,向多个对象中的一个提交请求。
  3. 需要动态指定一组对象处理请求,例如在运行时动态调整处理链。

责任链模式的变体

  1. 纯责任链模式:

    • 每个处理者要么处理请求,要么将请求传递给下一个处理者,但不能同时进行。
    • 这种模式通常用于严格的链式处理,例如审批流程。
  2. 不纯责任链模式:

    • 处理者可以部分处理请求,然后将请求传递给下一个处理者。
    • 这种模式允许处理者在处理请求的同时,继续传递请求,适用于需要多个处理者共同完成任务的场景。
  3. 带中断的责任链模式:

    • 处理者可以在处理请求后决定是否中断链的传递。
    • 这种模式适用于某些情况下,一旦请求被处理,就不需要继续传递的场景。
  4. 带优先级的责任链模式:

    • 处理者根据优先级决定是否处理请求,优先级高的处理者先处理请求。
    • 这种模式适用于需要根据优先级决定处理顺序的场景。

以下是基于责任链模式的不同变体的 C++ 代码示例。每个示例都展示了如何在 C++ 中实现责任链模式的不同形式。


1. 纯责任链模式

在纯责任链模式中,每个处理者要么处理请求,要么将请求传递给下一个处理者。处理者不会同时处理请求并传递请求。

#include <iostream>
#include <memory>class Handler {
public:virtual ~Handler() = default;virtual void setNext(std::shared_ptr<Handler>) = 0;virtual void handle(const std::string& request) = 0;
};class BaseHandler : public Handler {
protected:std::shared_ptr<Handler> nextHandler;public:void setNext(std::shared_ptr<Handler> handler) override {nextHandler = handler;}void handle(const std::string& request) override {if (nextHandler) {nextHandler->handle(request);}}
};class ConcreteHandlerA : public BaseHandler {
public:void handle(const std::string& request) override {if (request == "A") {std::cout << "ConcreteHandlerA handles request: " << request << std::endl;} else {BaseHandler::handle(request);}}
};class ConcreteHandlerB : public BaseHandler {
public:void handle(const std::string& request) override {if (request == "B") {std::cout << "ConcreteHandlerB handles request: " << request << std::endl;} else {BaseHandler::handle(request);}}
};int main() {auto handlerA = std::make_shared<ConcreteHandlerA>();auto handlerB = std::make_shared<ConcreteHandlerB>();handlerA->setNext(handlerB);handlerA->handle("B");  // ConcreteHandlerB handles request: BhandlerA->handle("A");  // ConcreteHandlerA handles request: AhandlerA->handle("C");  // No handler can process Creturn 0;
}


2. 不纯责任链模式

在不纯责任链模式中,处理者可以部分处理请求,然后将请求传递给下一个处理者。

#include <iostream>
#include <memory>class Handler {
public:virtual ~Handler() = default;virtual void setNext(std::shared_ptr<Handler>) = 0;virtual void handle(const std::string& request) = 0;
};class BaseHandler : public Handler {
protected:std::shared_ptr<Handler> nextHandler;public:void setNext(std::shared_ptr<Handler> handler) override {nextHandler = handler;}void handle(const std::string& request) override {if (nextHandler) {nextHandler->handle(request);}}
};class ConcreteHandlerA : public BaseHandler {
public:void handle(const std::string& request) override {if (request == "A") {std::cout << "ConcreteHandlerA handles request: " << request << std::endl;} else {std::cout << "ConcreteHandlerA partially processes request: " << request << std::endl;BaseHandler::handle(request);}}
};class ConcreteHandlerB : public BaseHandler {
public:void handle(const std::string& request) override {if (request == "B") {std::cout << "ConcreteHandlerB handles request: " << request << std::endl;} else {std::cout << "ConcreteHandlerB partially processes request: " << request << std::endl;BaseHandler::handle(request);}}
};int main() {auto handlerA = std::make_shared<ConcreteHandlerA>();auto handlerB = std::make_shared<ConcreteHandlerB>();handlerA->setNext(handlerB);handlerA->handle("B");  // ConcreteHandlerB handles request: BhandlerA->handle("A");  // ConcreteHandlerA handles request: AhandlerA->handle("C");  // ConcreteHandlerA partially processes request: C// ConcreteHandlerB partially processes request: Creturn 0;
}


3. 带中断的责任链模式

在带中断的责任链模式中,处理者可以在处理请求后决定是否中断链的传递。

#include <iostream>
#include <memory>class Handler {
public:virtual ~Handler() = default;virtual void setNext(std::shared_ptr<Handler>) = 0;virtual bool handle(const std::string& request) = 0;
};class BaseHandler : public Handler {
protected:std::shared_ptr<Handler> nextHandler;public:void setNext(std::shared_ptr<Handler> handler) override {nextHandler = handler;}bool handle(const std::string& request) override {if (nextHandler) {return nextHandler->handle(request);}return false;}
};class ConcreteHandlerA : public BaseHandler {
public:bool handle(const std::string& request) override {if (request == "A") {std::cout << "ConcreteHandlerA handles request: " << request << std::endl;return true;  // 中断链式传递}return BaseHandler::handle(request);}
};class ConcreteHandlerB : public BaseHandler {
public:bool handle(const std::string& request) override {if (request == "B") {std::cout << "ConcreteHandlerB handles request: " << request << std::endl;return true;  // 中断链式传递}return BaseHandler::handle(request);}
};int main() {auto handlerA = std::make_shared<ConcreteHandlerA>();auto handlerB = std::make_shared<ConcreteHandlerB>();handlerA->setNext(handlerB);handlerA->handle("B");  // ConcreteHandlerB handles request: BhandlerA->handle("A");  // ConcreteHandlerA handles request: AhandlerA->handle("C");  // No handler can process Creturn 0;
}


4. 带优先级的责任链模式

在带优先级的责任链模式中,处理者根据优先级决定是否处理请求,优先级高的处理者先处理请求。

#include <iostream>
#include <memory>
#include <vector>
#include <algorithm>class Handler {
public:virtual ~Handler() = default;virtual int getPriority() const = 0;virtual void handle(const std::string& request) = 0;
};class BaseHandler : public Handler {
protected:int priority;public:BaseHandler(int p) : priority(p) {}int getPriority() const override {return priority;}void handle(const std::string& request) override {// 默认不处理}
};class ConcreteHandlerA : public BaseHandler {
public:ConcreteHandlerA(int p) : BaseHandler(p) {}void handle(const std::string& request) override {if (request == "A") {std::cout << "ConcreteHandlerA handles request: " << request << std::endl;}}
};class ConcreteHandlerB : public BaseHandler {
public:ConcreteHandlerB(int p) : BaseHandler(p) {}void handle(const std::string& request) override {if (request == "B") {std::cout << "ConcreteHandlerB handles request: " << request << std::endl;}}
};int main() {auto handlerA = std::make_shared<ConcreteHandlerA>(2);auto handlerB = std::make_shared<ConcreteHandlerB>(1);std::vector<std::shared_ptr<Handler>> handlers = {handlerA, handlerB};// 根据优先级排序std::sort(handlers.begin(), handlers.end(), [](const auto& h1, const auto& h2) {return h1->getPriority() > h2->getPriority();});for (const auto& handler : handlers) {handler->handle("B");  // ConcreteHandlerB handles request: Bhandler->handle("A");  // ConcreteHandlerA handles request: A}return 0;
}


总结

以上代码示例展示了责任链模式的四种不同变体:

  1. 纯责任链模式:处理者要么处理请求,要么传递请求。
  2. 不纯责任链模式:处理者可以部分处理请求并传递请求。
  3. 带中断的责任链模式:处理者可以中断链的传递。
  4. 带优先级的责任链模式:处理者根据优先级决定处理顺序。

这些变体可以根据具体需求灵活选择和实现,以满足不同场景下的功能需求。

基于责任链模式特点的软件架构模式

  1. 中间件架构:

    • 在Web开发中,中间件架构通常使用责任链模式来处理HTTP请求。每个中间件都可以对请求进行处理,然后决定是否将请求传递给下一个中间件。
    • 例如,Express.js中的中间件机制就是基于责任链模式实现的。
  2. 事件处理系统:

    • 在GUI编程中,事件处理系统通常使用责任链模式来处理用户事件。每个事件处理器可以处理事件,或者将事件传递给下一个处理器。
    • 例如,Java AWT/Swing中的事件处理机制就是基于责任链模式实现的。
  3. 工作流引擎:

    • 在工作流引擎中,责任链模式可以用于处理工作流中的各个步骤。每个步骤可以处理任务,或者将任务传递给下一个步骤。
    • 例如,Activiti等工作流引擎中的任务处理机制就是基于责任链模式实现的。
  4. 过滤器链:

    • 在Web应用中,过滤器链通常使用责任链模式来处理请求和响应。每个过滤器可以对请求或响应进行处理,然后将其传递给下一个过滤器。
    • 例如,Java Servlet中的过滤器机制就是基于责任链模式实现的。

总结

责任链模式通过将请求的发送者和接收者解耦,提供了一种灵活的方式来处理请求。它适用于多个对象可以处理同一请求的场景,并且可以通过不同的变体来满足不同的需求。基于责任链模式的特点,许多软件架构模式(如中间件架构、事件处理系统、工作流引擎和过滤器链)都采用了这种模式来实现灵活的处理机制。

相关文章:

C++软件设计模式之责任链模式

责任链模式的动机与意图 动机&#xff1a; 在软件开发中&#xff0c;经常会遇到需要处理一系列请求或事件的情况。这些请求可能需要经过多个处理对象&#xff0c;每个对象根据其职责决定是否处理请求或将其传递给下一个对象。责任链模式&#xff08;Chain of Responsibility P…...

021-spring-springmvc-组件

SpringMVC的handMapping 比较重要的部分 比较重要的部分 比较重要的部分 关于组件的部分 这里以 RequestMappingHandlerMapping 为例子 默认的3个组件是&#xff1a; org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping org.springframework.web.servlet.mvc…...

基于SpringBoot和OAuth2,实现通过Github授权登录应用

基于SpringBoot和OAuth2&#xff0c;实现通过Github授权登录应用 文章目录 基于SpringBoot和OAuth2&#xff0c;实现通过Github授权登录应用0. 引言1. 创建Github应用2. 创建SpringBoot测试项目2.1 初始化项目2.2 设置配置文件信息2.3 创建Controller层2.4 创建Html页面 3. 启动…...

macos 支持外接高分辩率显示器开源控制软件

macos 支持外接高分辩率显示器开源控制软件 软件&#xff08;app应用&#xff09;名&#xff1a;BetterDisplay 官方地址&#xff1a; https://github.com/waydabber/BetterDisplay...

C++26 新特性预览(Preview)

文章目录 1. 静态反射 (Static Reflection)示例: 枚举转字符串应用场景 2. 合约 (Contracts)示例: 定义函数合约应用场景 3. 条件中的结构化绑定 (Structured Bindings in Conditions)示例: 改进的错误处理应用场景 4. 包索引 (Pack Indexing)示例: 获取参数包的第一个和最后一…...

MySQL5.7.26-Linux-安装(2024.12)

文章目录 1.下载压缩包1.访问MySQL版本归档2.找到5.7.26并下载3.百度网盘 2.Linux安装1.卸载原来的MySQL8.0.26&#xff08;如果没有则无需在意&#xff09;1.查看所有mysql的包2.批量卸载3.删除残留文件**配置文件**&#xff08;默认路径&#xff09;&#xff1a; 4.**验证卸载…...

2025-1-2-sklearn学习(30)模型选择与评估-验证曲线: 绘制分数以评估模型 真珠帘卷玉楼空,天淡银河垂地。

文章目录 sklearn学习(30) 模型选择与评估-验证曲线: 绘制分数以评估模型30.1. 验证曲线30.2. 学习曲线 sklearn学习(30) 模型选择与评估-验证曲线: 绘制分数以评估模型 文章参考网站&#xff1a; https://sklearn.apachecn.org/ 和 https://scikit-learn.org/stable/ 每种估…...

【优选算法】查找总价格为目标值的两个商品

链接&#xff1a;LCR 179. 查找总价格为目标值的两个商品 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a;利用单调性&#xff0c;使用双指针算法解决问题 1.先从小到大排序 2. sum > t : right--; sum < t : left; sum t : return class Solution {public…...

利用 NineData 实现 PostgreSQL 到 Kafka 的高效数据同步

记录一次 PostgreSQL 到 Kafka 的数据迁移实践。前段时间&#xff0c;NineData 的某个客户在一个项目中需要将 PostgreSQL 的数据实时同步到 Kafka。需求明确且普遍&#xff1a; PostgreSQL 中的交易数据&#xff0c;需要实时推送到 Kafka&#xff0c;供下游多个系统消费&#…...

future和CompletableFuture

future 什么是future Future 类是并发编程中一个非常重要的工具。它主要用于表示一个异步计算的结果&#xff0c;允许你在计算完成后获取结果或处理异常。Java 的 Future 也常常与线程池&#xff08;如 ExecutorService&#xff09;结合使用&#xff0c;用来执行并行任务&…...

如何通过深度学习提升大分辨率图像预测准确率?

随着科技的不断进步&#xff0c;图像处理在各个领域的应用日益广泛&#xff0c;特别是在医疗影像、卫星遥感、自动驾驶、安防监控等领域中&#xff0c;大分辨率图像的使用已经成为了一项不可或缺的技术。然而&#xff0c;大分辨率图像带来了巨大的计算和存储压力&#xff0c;同…...

【机器学习】机器学习的基本分类-半监督学习-Ladder Networks

Ladder Networks 是一种半监督学习模型&#xff0c;通过将无监督学习与监督学习相结合&#xff0c;在标记数据较少的情况下实现高效的学习。它最初由 A. Rasmus 等人在 2015 年提出&#xff0c;特别适合深度学习任务&#xff0c;如图像分类或自然语言处理。 核心思想 Ladder N…...

[react]小技巧, ts如何声明点击事件的类型

很简单, 鼠标放到事件上面就行了 如果想知道点击的是什么元素 ,打印他的nodename就行了 不过得断言为html元素才行 const handleClick (e: React.MouseEvent<HTMLDivElement, MouseEvent>) > {console.log(current, (e.target as HTMLElement).nodeName);}; 为什么…...

智能工厂的设计软件 应用场景的一个例子:为AI聊天工具添加一个知识系统 之9 重新开始 之2

本文要点 对程序设计而言&#xff1a;前者基于一个自上而下的 分类体系--&#xff08;生物遗传基因&#xff09;&#xff0c;后者者需要一个收集差异的自下而上的差异继承路径--&#xff08;系统继承源流&#xff09; 就是 广义和狭义 分类学。 共性对齐 和 差异收集 正是两者…...

【从零开始】11. LLaMA-Factory 微调 Qwen 模型(番外篇)

书接上回&#xff0c;在完成了 RAGChecker 测试后&#xff0c;离 RAG 应用真正发布还差最后一步 - 基础信息指令微调。考虑到模型还是需要具备一定程度的“自我认知”&#xff0c;因此需要将公司信息“嵌入”到模型里面的。为此&#xff0c;我选择了 LLaMA-Factory&#xff08;…...

WPF使用ContentControl控件实现区域导航,并使用Prism依赖注入优化

背景&#xff1a;使用ContentControl控件实现区域导航是有Mvvm框架的WPF都能使用的&#xff0c;不限于Prism 主要是将ContenControl控件的Content内容在ViewModel中切换成不同的用户控件 下面是MainViewModel&#xff1a; private object body;public object Body {get { retu…...

JavaWeb——MySQL-DML(1/3)-添加数据insert(DML 操作概述、INSERT 语句插入数据、语句演示、总结)

目录 DML 操作概述 INSERT 语句插入数据 INSERT 语句基础语法 INSERT 语句演示 注意事项 总结 DML 操作概述 DML 简介 DML&#xff08;Data Manipulation Language&#xff09;即数据操作语言&#xff0c;用于对数据库表中的数据进行增删改操作&#xff0c;包括添加数据&…...

经验证:将数据从索尼传输到Android的 4 种方法

概括 像Android Galaxy S20 这样的新型Android智能手机很酷&#xff0c;但除了将数据从索尼传输到Android之外。众所周知&#xff0c;旧的索尼手机上存储着大量的文件&#xff0c;因此将数据从旧的索尼手机传输到新的Android手机非常重要。为了解决这个问题&#xff0c;我们做…...

嵌入式应用实例→电子产品量产工具→UI界面的绘制和测试

前言 之前已经在博文https://blog.csdn.net/wenhao_ir/article/details/144747714中实现了用Freetype在LCD屏上绘制字符&#xff0c;本篇博文我们利用Freetype实现UI界面的绘制。 头文件include\ui.h的分析 头文件内的代码 #ifndef _UI_H #define _UI_H#include <common…...

如何删除 Docker 中的悬虚镜像?

在 Docker 中&#xff0c;悬虚镜像&#xff08;Dangling Images&#xff09;是指那些没有 标签 且没有被任何容器使用的镜像。这些镜像通常是由于构建过程中生成的中间层镜像或未正确清理的镜像残留。删除悬虚镜像可以释放磁盘空间并保持 Docker 环境的整洁。 1. 列出悬虚镜像…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

java_网络服务相关_gateway_nacos_feign区别联系

1. spring-cloud-starter-gateway 作用&#xff1a;作为微服务架构的网关&#xff0c;统一入口&#xff0c;处理所有外部请求。 核心能力&#xff1a; 路由转发&#xff08;基于路径、服务名等&#xff09;过滤器&#xff08;鉴权、限流、日志、Header 处理&#xff09;支持负…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统

医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上&#xff0c;开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识&#xff0c;在 vs 2017 平台上&#xff0c;进行 ASP.NET 应用程序和简易网站的开发&#xff1b;初步熟悉开发一…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

NFT模式:数字资产确权与链游经济系统构建

NFT模式&#xff1a;数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新&#xff1a;构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议&#xff1a;基于LayerZero协议实现以太坊、Solana等公链资产互通&#xff0c;通过零知…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...