【第21节】C++设计模式(行为模式)-Chain of Responsibility(责任链)模式
一、问题背景
在 VC/MFC 开发中,消息处理机制是核心部分之一。VC 是基于消息和事件驱动的框架,消息的处理流程通常是通过链式传递的方式进行的。例如,一个 `WM_COMMAND` 消息的处理流程可能如下:
(1)MDI 主窗口(CMDIFrameWnd)  收到命令消息 `WM_COMMAND`,其 ID 为 `ID_×××`。
 (2)MDI 主窗口  将消息传递给当前活动的 **MDI 子窗口(CMDIChildWnd)**。
 (3)MDI 子窗口  将消息交给其子窗口 **View** 处理。
 (4)View  检查自己的消息映射表(Message Map)。
 (5)如果  View  没有处理该消息的程序,则将消息传递给其对应的 **Document** 对象。
 (6)Document  检查自己的消息映射表,如果没有处理程序,则将消息传递给其 **DocumentTemplate** 处理。
 (7)如果消息在 **Document** 中仍未得到处理,则消息返回给 **View**。
 (8)View  将消息传回给 **MDI 子窗口**。
 (9)MDI 子窗口** 将消息传递给 **CWinApp** 对象,**CWinApp** 为所有无主的消息提供了默认处理。
这种链式处理策略使得消息的发送者无需知道消息最终由哪个对象处理,只需将消息传递给链中的第一个对象即可。这种设计模式正是 **Chain of Responsibility(责任链)模式** 的典型应用。
二、模式选择
Chain of Responsibility 模式的核心思想是将多个处理对象连接成一条链,请求沿着链传递,直到某个对象处理它为止。这种模式的主要优点在于:
(1)降低耦合性:请求的发送者无需知道具体的处理者,只需将请求传递给链中的第一个对象。
 (2)动态处理:可以在运行时动态地调整链中的处理对象。
 (3)灵活性:可以灵活地增加或删除处理对象。
Chain of Responsibility 模式的典型结构图如下:

在 Chain of Responsibility 模式中,每个 `ConcreteHandler` 对象都维护一个指向其后继者的引用。当一个请求到来时,`ConcreteHandler` 会先检查自己是否能处理该请求。如果不能,则将请求传递给后继者。
三、代码实现
下面我们将通过一个完整的 C++ 代码示例来展示如何实现 Chain of Responsibility 模式。
代码片段 1:Handle.h
// Handle.h
#ifndef _HANDLE_H_
#define _HANDLE_H_class Handle {
public:virtual ~Handle();virtual void HandleRequest() = 0;  // 处理请求的接口void SetSuccessor(Handle* succ);   // 设置后继者Handle* GetSuccessor();            // 获取后继者protected:Handle();Handle(Handle* succ);private:Handle* _succ;  // 后继者对象
};// ConcreteHandleA 类
class ConcreteHandleA : public Handle {
public:ConcreteHandleA();~ConcreteHandleA();ConcreteHandleA(Handle* succ);void HandleRequest();  // 处理请求的具体实现protected:
private:
};// ConcreteHandleB 类
class ConcreteHandleB : public Handle {
public:ConcreteHandleB();~ConcreteHandleB();ConcreteHandleB(Handle* succ);void HandleRequest();  // 处理请求的具体实现protected:
private:
};#endif //~_HANDLE_H_ 
代码片段 2:Handle.cpp
// Handle.cpp
#include "Handle.h"
#include <iostream>
using namespace std;// Handle 类的实现
Handle::Handle() {_succ = nullptr;  // 初始化后继者为空
}Handle::~Handle() {delete _succ;  // 释放后继者对象
}Handle::Handle(Handle* succ) {_succ = succ;  // 设置后继者
}void Handle::SetSuccessor(Handle* succ) {_succ = succ;  // 设置后继者
}Handle* Handle::GetSuccessor() {return _succ;  // 获取后继者
}void Handle::HandleRequest() {// 默认实现为空
}// ConcreteHandleA 类的实现
ConcreteHandleA::ConcreteHandleA() {// 构造函数
}ConcreteHandleA::~ConcreteHandleA() {// 析构函数
}ConcreteHandleA::ConcreteHandleA(Handle* succ) : Handle(succ) {// 构造函数
}void ConcreteHandleA::HandleRequest() {if (this->GetSuccessor() != nullptr) {cout << "ConcreteHandleA 我把处理权给后继节点....." << endl;this->GetSuccessor()->HandleRequest();  // 将请求传递给后继者} else {cout << "ConcreteHandleA 没有后继了,我必须自己处理...." << endl;}
}// ConcreteHandleB 类的实现
ConcreteHandleB::ConcreteHandleB() {// 构造函数
}ConcreteHandleB::~ConcreteHandleB() {// 析构函数
}ConcreteHandleB::ConcreteHandleB(Handle* succ) : Handle(succ) {// 构造函数
}void ConcreteHandleB::HandleRequest() {if (this->GetSuccessor() != nullptr) {cout << "ConcreteHandleB 我把处理权给后继节点....." << endl;this->GetSuccessor()->HandleRequest();  // 将请求传递给后继者} else {cout << "ConcreteHandleB 没有后继了,我必须自己处理...." << endl;}
} 
代码片段 3:main.cpp
// main.cpp
#include "Handle.h"
#include <iostream>
using namespace std;int main(int argc, char* argv[]) {// 创建责任链中的处理对象Handle* h1 = new ConcreteHandleA();Handle* h2 = new ConcreteHandleB();// 设置责任链的顺序h1->SetSuccessor(h2);// 处理请求h1->HandleRequest();// 释放内存delete h1;delete h2;return 0;
} 
代码说明
(1)Handle 类:`Handle` 是抽象基类,定义了处理请求的接口 `HandleRequest`,并提供了设置和获取后继者的方法。
 (2)ConcreteHandleA 和 ConcreteHandleB:这两个类是具体的处理者,实现了 `HandleRequest` 方法。如果它们无法处理请求,则将请求传递给后继者。
 (3)责任链的构建:在 `main.cpp` 中,我们创建了两个处理对象 `h1` 和 `h2`,并通过 `SetSuccessor` 方法将它们连接成一条链。当请求到来时,`h1` 会先尝试处理请求,如果无法处理,则将请求传递给 `h2`。
运行结果
程序的输出如下:
ConcreteHandleA 我把处理权给后继节点.....
ConcreteHandleB 没有后继了,我必须自己处理....
四、总结讨论
Chain of Responsibility 模式的最大优点在于它降低了系统的耦合性。请求的发送者无需知道具体的处理者,只需将请求传递给责任链中的第一个对象即可。这种设计模式非常适合以下场景:
(1)多级处理:当请求需要经过多个对象处理时,可以使用责任链模式。
 (2)动态处理:可以在运行时动态地调整责任链中的处理对象。
 (3)解耦:请求的发送者和处理者之间完全解耦,系统更加灵活。
Chain of Responsibility 模式通过将多个处理对象连接成一条链,使得请求可以沿着链传递,直到某个对象处理它为止。这种模式不仅降低了系统的耦合性,还提高了系统的灵活性和可扩展性。在实际开发中,责任链模式可以广泛应用于消息处理、事件处理等场景。
相关文章:
【第21节】C++设计模式(行为模式)-Chain of Responsibility(责任链)模式
一、问题背景 在 VC/MFC 开发中,消息处理机制是核心部分之一。VC 是基于消息和事件驱动的框架,消息的处理流程通常是通过链式传递的方式进行的。例如,一个 WM_COMMAND 消息的处理流程可能如下: (1)MDI 主窗…...
createrepo centos通过nginx搭建本地源
yum update 先安装一个nginx。 安装Nginx yum install gcc gcc-c pcre pcre-devel openssl openssl-devel libtool zlib zlib-devel -y cd /usr/local/src wget http://nginx.org/download/nginx-1.22.0.tar.gz tar -zxvf nginx-1.22.0.tar.gz cd nginx-1.22.0 ./configu…...
在 Docker 中搭建GBase 8s主备集群环境
本文介绍了如何在同一台机器上使用 Docker 容器搭建GBase 8s主备集群环境。 拉取镜像 拉取GBase 8s的最新镜像 docker pull liaosnet/gbase8s或者docker pull liaosnet/gbase8s:v8.8_3513x25_csdk_x64注:在tag为v8.8_3513x25_csdk_x64及之后的版本中,…...
【MySQL-数据类型】数据类型分类+数值类型+文本、二进制类型+String类型
一、数据类型分类 二、数值类型 1.bit类型 测试环境ubuntu 基本语法: bit[(M)]:位字段类型,M表示每个值的位数,范围从1~64;如果M被忽略,默认为1举例: create table testBit(id i…...
小谈java内存马
基础知识 (代码功底不好,就找ai优化了一下) Java内存马是一种利用Java虚拟机(JVM)动态特性(如类加载机制、反射技术等)在内存中注入恶意代码的攻击手段。它不需要在磁盘上写入文件,…...
简单的二元语言模型bigram实现
内容总结归纳自视频:【珍藏】从头开始用代码构建GPT - 大神Andrej Karpathy 的“神经网络从Zero到Hero 系列”之七_哔哩哔哩_bilibili 项目:https://github.com/karpathy/ng-video-lecture Bigram模型是基于当前Token预测下一个Token的模型。例如&#x…...
【清华大学】实用DeepSeek赋能家庭教育 56页PDF文档完整版
清华大学-56页:实用DeepSeek赋能家庭教育.pdf https://pan.baidu.com/s/1BUweVDeG2M8-t0QaIs3LHQ?pwd1234 提取码: 1234 或 https://pan.quark.cn/s/8a9473493bb0 《实用DeepSeek赋能家庭教育》基于清华大学研究成果,系统阐述了DeepSeek人工智能技…...
黑洞如何阻止光子逃逸
虽然涉及广义相对论,但广义相对论说的是大质量物体对周围空间的影响,而不是说周围空间和空间中的光子之间的关系。也就是说,若讨论光子逃逸问题,则不必限定于大质量的前提,也就是说,若质量周围被扭曲的空间…...
1.4 单元测试与热部署
本次实战实现Spring Boot的单元测试与热部署功能。单元测试方面,通过JUnit和Mockito等工具,结合SpringBootTest注解,可以模拟真实环境对应用组件进行独立测试,验证逻辑正确性,提升代码质量。具体演示了HelloWorld01和H…...
window系统中的start命令详解
start 是 Windows 系统中用于启动新进程或打开新窗口来运行指定程序或命令的命令。以下是对 start 命令参数的详细解释: 基本语法 start ["title"] [/Dpath] [/I] [/MIN] [/MAX] [/SEPARATE | /SHARED] [/LOW | /NORMAL | /HIGH | /REALTIME | /ABOVENO…...
AI编程工具节选
1、文心快码 百度基于文心大模型推出的一款智能编码助手, 官网地址:文心快码(Baidu Comate)更懂你的智能代码助手 2、通义灵码 阿里云出品的一款基于通义大模型的智能编码辅助工具, 官网地址:通义灵码_你的智能编码助手-阿里云 …...
正则表达式,idea,插件anyrule
package lx;import java.util.regex.Pattern;public class lxx {public static void main(String[] args) {//正则表达式//写一个电话号码的正则表达式String regex "1[3-9]\\d{9}";//第一个数字是1,第二个数字是3-9,后面跟着9个数字…...
原生iOS集成react-native (react-native 0.65+)
由于官方文档比较老,很多配置都不能用,集成的时候遇到很多坑,简单的整理一下 时间节点:2021年9月1日 本文主要提供一些配置信息以及错误信息解决方案,具体步骤可以参照官方文档 原版文档:https://reactnative.dev/docs…...
java错题总结
本篇文章用来记录学习javaSE以来的错题 解答:重载要求俩个方法的名字相同,但参数的类型或者个数不同,但是不要求返回类型相同,所以A正确。 重写还需要要求返回类型相同(呈现父子类关系也可以,但是属于特例&…...
【商城实战(10)】解锁商品信息录入与展示的技术密码
【商城实战】专栏重磅来袭!这是一份专为开发者与电商从业者打造的超详细指南。从项目基础搭建,运用 uniapp、Element Plus、SpringBoot 搭建商城框架,到用户、商品、订单等核心模块开发,再到性能优化、安全加固、多端适配…...
2025年主流原型工具测评:墨刀、Axure、Figma、Sketch
2025年主流原型工具测评:墨刀、Axure、Figma、Sketch 要说2025年国内产品经理使用的主流原型设计工具,当然是墨刀、Axure、Figma和Sketch了,但是很多刚入行的产品经理不了解自己适合哪些工具,本文将从核心优势、局限短板、协作能…...
MDM 如何彻底改变医疗设备的远程管理
在现代医疗行业迅速发展的格局中,医院和诊所越来越依赖诸如医疗平板和移动工作站等移动设备。这些设备在提高工作效率和提供卓越的患者护理方面发挥着关键作用。然而,随着它们的广泛使用,也带来了一系列挑战,例如在不同地点确保数…...
OpenCV计算摄影学(18)平滑图像中的纹理区域同时保留边缘信息函数textureFlattening()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::textureFlattening 是 OpenCV 中用于图像处理的一个函数,旨在平滑图像中的纹理区域,同时保留边缘信息。该技术特别适…...
用DeepSeek学Android开发:Android初学者遇到的常见问题有哪些?如何解决?
答案来自 DeepSeek Q: Android初学者遇到的常见问题有哪些?如何解决? A: Android初学者在学习过程中常会遇到以下问题及对应的解决方法,按类别整理如下: 一、开发环境问题 Android Studio安装或配置问题 问题:安装失…...
springboot 集成 MongoDB 基础篇
demo架构: Book Controller: package com.zy.controller;import com.zy.entity.Book; import com.zy.service.MongoDbService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.Get…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
04-初识css
一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
