【第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…...
抖音图片怎么去水印?2026年在线去水印工具+方法盘点,总有一款适合你
开篇:为什么要去水印? 保存抖音图片时,总会遇到水印的困扰。这些水印包含抖音logo、发布者名称,有时还会有账号信息。对于自媒体创作者、内容整理者或普通用户来说,去除水印往往是必需的。本文将介绍当下最实用的抖音图…...
Altium Designer实战:用xSignals搞定DDR4内存的等长布线,告别时序烦恼
Altium Designer实战:用xSignals实现DDR4内存精准等长布线 在高速PCB设计中,DDR4内存接口的布线一直是硬件工程师面临的技术高地。当信号速率突破2400MHz时,地址、命令与数据线之间哪怕几个ps的时序偏差都可能导致系统不稳定。传统手工计算网…...
基于Groq LPU与React技术栈构建极速AI聊天应用实战
1. 项目概述:当极速推理遇上聊天应用最近在折腾AI应用开发的朋友,估计都绕不开一个词:推理速度。模型能力再强,如果生成一句话要等上十几秒,用户体验就无从谈起。正是在这种背景下,我注意到了unclecode/gro…...
终极指南:如何使用League-Toolkit英雄联盟工具箱快速提升游戏效率
终极指南:如何使用League-Toolkit英雄联盟工具箱快速提升游戏效率 【免费下载链接】League-Toolkit An all-in-one toolkit for LeagueClient. Gathering power 🚀. 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit 还在为英雄联盟中…...
KIVI开源工具箱:模块化设计赋能开发者效率提升
1. 项目概述:一个面向开发者的开源工具箱最近在GitHub上闲逛,发现了一个挺有意思的项目,叫KIVI。第一眼看到这个名字,我以为是某种新的UI框架或者设计系统,毕竟“KIVI”听起来有点像是“Kiwi”的变体,容易联…...
ComfyUI-Manager终极指南:3步掌握AI绘画插件管理技巧
ComfyUI-Manager终极指南:3步掌握AI绘画插件管理技巧 【免费下载链接】ComfyUI-Manager ComfyUI-Manager is an extension designed to enhance the usability of ComfyUI. It offers management functions to install, remove, disable, and enable various custom…...
用STM32+LoRa+阿里云IoT Studio,我DIY了一个低成本畜牧电子围栏(附完整代码)
基于STM32与LoRa的智能畜牧围栏系统开发实战 在广袤的牧区,牲畜走失一直是困扰牧民的核心问题。传统物理围栏不仅成本高昂,在草原这类开放地形中实施难度也很大。本文将详细介绍如何利用STM32微控制器、LoRa远距离通信模块和阿里云IoT Studio平台&#x…...
【最新 v2.7.1 版本安装包】零基础也能流畅使用,OpenClaw 无需命令一键部署保姆级教程
OpenClaw(小龙虾)Windows 一键部署保姆级教程 | 10 分钟搭建专属数字员工【点击下载最新OpenClaw安装包】 前言 2026 年开源圈热门 AI 智能体 OpenClaw(昵称小龙虾),GitHub 星标突破 28 万,凭借本地运行 …...
MQ-3与MiCS-5524气体传感器对比:从原理到实战的选型指南
1. 项目概述与核心价值在嵌入式开发、环境监测乃至一些创意DIY项目中,气体检测是一个常见且关键的需求。无论是为了安全预警(如天然气泄漏),还是进行环境质量评估(如VOC监测),选择一款合适的传感…...
Claude模型思维链评估框架claweval:原理、实战与高级定制指南
1. 项目概述:一个专为Claude模型设计的“思维链”评估框架最近在AI应用开发圈里,一个名为claweval的项目开始被频繁提及。如果你正在使用Anthropic的Claude系列模型(无论是Claude 3 Opus、Sonnet还是Haiku)来构建需要复杂推理能力…...
