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

C++设计模式-责任链模式:从基本介绍,内部原理、应用场景、使用方法,常见问题和解决方案进行深度解析

一、责任链模式的基本介绍

1.1 模式定义与核心思想

责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,其核心思想是将请求的发送者和接收者解耦。通过创建一个由多个处理节点组成的链条,每个节点依次尝试处理请求。如果当前节点无法处理,则将请求传递给链中的下一个节点,直到找到合适的处理者或链尾。
这种模式的灵感来源于现实中的链式处理流程,例如:

  • 公司请假审批(员工→部门经理→总经理)
  • 电商订单处理(支付→库存→物流)
  • 操作系统事件处理(键盘→鼠标→触摸板)

1.2 模式本质与设计原则

责任链模式通过以下方式实现设计目标:

  • 单一职责原则:每个处理节点专注于特定类型的请求
  • 开闭原则:新增处理节点时无需修改现有代码
  • 解耦:请求发送者与接收者之间无直接依赖关系
  • 灵活性:处理顺序可动态调整

1.3 模式结构与角色

责任链模式包含以下核心角色:

  • 抽象处理者(Handler):
    定义处理请求的接口(handleRequest);
    维护下一个处理者的引用;
  • 具体处理者(ConcreteHandler):
    实现具体的请求处理逻辑;
    决定是否传递请求给下一个节点
  • 客户端(Client):
    创建责任链;
    提交请求到链的起始节点;

类结构如下:

class Handler {
public:virtual ~Handler() = default;virtual void handleRequest(Request* request) = 0;void setNext(Handler* next) { nextHandler = next; }
protected:Handler* nextHandler = nullptr;
};class ConcreteHandlerA : public Handler {
public:void handleRequest(Request* request) override {if (canHandle(request)) {// 处理请求} else {if (nextHandler) {nextHandler->handleRequest(request);}}}
private:bool canHandle(Request* request) { /* 判断逻辑 */ }
};

二、责任链模式的内部原理

2.1 请求传递机制

责任链的核心在于请求的传递逻辑:

  • 客户端将请求发送到链的起始节点;
  • 当前节点检查是否能处理请求;
  • 能处理则执行处理逻辑;
  • 不能处理则传递给下一个节点;
  • 直到请求被处理或到达链尾;

代码示例:

class Manager : public Handler {
public:void handleRequest(Request* request) override {if (request->type == RequestType::Leave) {if (request->days <= 3) {cout << "Manager approved " << request->days << " days leave" << endl;} else {if (nextHandler) {nextHandler->handleRequest(request);}}}}
};

2.2 责任链的构建方式

责任链的构建通常有两种方式:
客户端构建:客户端负责组装各个处理节点

auto ceo = new CEO();
auto director = new Director();
director->setNext(ceo);
auto manager = new Manager();
manager->setNext(director);

动态构建:通过配置文件或依赖注入动态生成链

2.3 处理顺序的控制

处理顺序对系统行为有重要影响:

  • 正向链:处理顺序由低到高(如初级到高级审批)
  • 反向链:优先尝试高级处理者
  • 动态调整:根据运行时条件改变处理顺序

示例:日志级别处理链:

void LoggerChain::addLogger(Logger* logger) 
{if (!firstLogger) {firstLogger = logger;}else {currentLogger->setNext(logger);}currentLogger = logger;
}

三、责任链模式的应用场景

3.1 典型应用场景

  • 审批流程:请假、报销、订单审核;
  • 请求处理:Web 请求过滤(身份验证→权限检查→日志记录);
  • 事件处理:图形界面的事件传递;
  • 错误处理:异常处理链;
  • 职责划分:复杂任务的分步处理;

3.2 企业级应用案例

案例 1:电商订单处理

// 支付处理
PaymentHandler paymentHandler;
// 库存检查
InventoryHandler inventoryHandler;
inventoryHandler.setNext(&paymentHandler);
// 物流调度
ShippingHandler shippingHandler;
shippingHandler.setNext(&inventoryHandler);
// 执行处理
shippingHandler.handleOrder(order);

案例 2:Web 请求处理

FilterChain filterChain;
filterChain.addFilter(new AuthenticationFilter());
filterChain.addFilter(new AuthorizationFilter());
filterChain.addFilter(new LoggingFilter());
filterChain.doFilter(request, response);

3.3 模式适用条件

当系统满足以下条件时适合使用责任链模式:

  • 请求的处理流程包含多个步骤;
  • 处理步骤的顺序可能动态变化;
  • 需要灵活地新增或删除处理步骤;
  • 需要避免请求发送者与接收者之间的直接耦合;

四、责任链模式的使用方法

4.1 实现步骤详解

  • 定义请求类
class Request {
public:enum class Type { Leave, Overtime, Reimbursement };Type type;int days;double amount;
};
  • 创建抽象处理者
class Approver : public Handler {
public:virtual bool canApprove(Request* request) = 0;void handleRequest(Request* request) override {if (canApprove(request)) {processRequest(request);} else {if (nextHandler) {nextHandler->handleRequest(request);}}}
protected:virtual void processRequest(Request* request) = 0;
};
  • 实现具体处理者
class TeamLeader : public Approver {
public:bool canApprove(Request* request) override {return request->type == Request::Type::Leave && request->days <= 2;}
protected:void processRequest(Request* request) override {cout << "Team leader approved " << request->days << " days leave" << endl;}
};
  • 构建责任链
auto ceo = new CEO();
auto director = new Director();
director->setNext(ceo);
auto manager = new Manager();
manager->setNext(director);
auto teamLeader = new TeamLeader();
teamLeader->setNext(manager);
  • 提交请求
Request* request = new Request{Request::Type::Leave, 5};
teamLeader->handleRequest(request);

4.2 代码实现技巧

  • 模板方法模式结合:将公共处理逻辑上移到抽象类
  • 请求类型枚举:使用 enum 或类型标签标识请求类型
  • 智能指针管理链:使用 std::shared_ptr 防止内存泄漏
  • 链式调用:提供便捷的 addNext 方法简化链构建

示例:智能指针管理

using HandlerPtr = std::shared_ptr<Handler>;class Handler {
public:void setNext(HandlerPtr next) { nextHandler = next; }
private:HandlerPtr nextHandler;
};

五、常见问题及解决方案

5.1 常见问题分析

  • 问题 1:责任链终止条件不明确:
    现象:请求到达链尾仍未被处理;
    原因:缺少最终处理节点或条件判断错误;
  • 问题 2:处理顺序混乱:
    现象:请求被错误的处理者处理;
    原因:链的组装顺序错误;
  • 问题 3:性能问题:
    现象:链过长导致处理延迟;
    原因:线性遍历所有节点;
  • 问题 4:循环依赖:
    现象:节点间相互引用导致内存泄漏;
    原因:链构建时形成闭环;

5.2 解决方案

方案 1:设置默认处理者

class FallbackHandler : public Handler {
public:void handleRequest(Request* request) override {cout << "Request " << request->type << " cannot be handled" << endl;}
};// 使用时添加到链尾
teamLeader->setNext(fallbackHandler);

方案 2:责任链验证机制

void validateChain(Handler* handler) {std::set<Handler*> visited;while (handler) {if (visited.count(handler)) {throw std::runtime_error("Cycle detected in chain");}visited.insert(handler);handler = handler->getNext();}
}

方案 3:优化处理逻辑

  • 提前终止:在能处理的节点立即返回;
  • 缓存处理结果:避免重复计算;
  • 并行处理:使用多线程处理独立节点;

方案 4:使用组合模式
将多个处理者组合成复合处理者:

class CompositeHandler : public Handler {
public:void addHandler(Handler* handler) { handlers.push_back(handler); }void handleRequest(Request* request) override {for (auto& handler : handlers) {if (handler->canHandle(request)) {handler->handleRequest(request);return; // 找到第一个匹配的处理者}}// 传递给下一个节点if (nextHandler) {nextHandler->handleRequest(request);}}
private:std::vector<Handler*> handlers;
};

六、总结与最佳实践

6.1 模式优点

  • 解耦请求与处理:客户端无需知道具体处理者;
  • 灵活扩展:新增处理者只需修改链结构;
  • 动态控制:可以在运行时调整处理顺序;
  • 单一职责:每个处理者专注特定功能;

6.2 模式缺点

  • 调试困难:请求的传递路径难以跟踪;
  • 性能损耗:链过长会导致处理时间增加;
  • 资源消耗:每个请求可能遍历整个链;
  • 责任分散:可能导致职责划分不清晰;

6.3 最佳实践建议

  • 明确链的终止条件:始终包含一个最终处理者;
  • 控制链的长度:避免过多的处理节点;
  • 使用日志记录:记录请求的处理路径;
  • 优先使用组合而非继承:通过组合方式构建链;
  • 考虑性能优化:对于高频请求使用缓存或索引;

6.4 未来发展趋势

  • 与响应式编程结合:利用 Rx 链处理异步请求;
  • 智能链优化:根据历史数据动态调整处理顺序;
  • 云原生适配:在微服务架构中实现跨服务责任链;
  • AOP 集成:通过 Aspect-Oriented Programming 增强处理逻辑;

附上一个完整的代码示例:

#include <iostream>
#include <memory>using namespace std;// 请求类
class Request {
public:enum class Type { Leave, Overtime, Reimbursement };Type type;int days;double amount;
};// 抽象处理者
class Approver {
public:virtual bool canApprove(Request* request) = 0;virtual void processRequest(Request* request) = 0;void handleRequest(Request* request) {if (canApprove(request)) {processRequest(request);} else {if (next) {next->handleRequest(request);} else {cout << "Request cannot be handled" << endl;}}}void setNext(unique_ptr<Approver> n) { next = move(n); }
private:unique_ptr<Approver> next;
};// 具体处理者
class TeamLeader : public Approver {
public:bool canApprove(Request* request) override {return request->type == Request::Type::Leave && request->days <= 2;}void processRequest(Request* request) override {cout << "Team leader approved " << request->days << " days leave" << endl;}
};class Manager : public Approver {
public:bool canApprove(Request* request) override {return request->type == Request::Type::Leave && request->days <= 5;}void processRequest(Request* request) override {cout << "Manager approved " << request->days << " days leave" << endl;}
};class Director : public Approver {
public:bool canApprove(Request* request) override {return request->type == Request::Type::Leave && request->days <= 10;}void processRequest(Request* request) override {cout << "Director approved " << request->days << " days leave" << endl;}
};// 客户端代码
int main() {// 构建责任链auto ceo = make_unique<Approver>(); // 假设CEO处理所有超过10天的请求auto director = make_unique<Director>();director->setNext(move(ceo));auto manager = make_unique<Manager>();manager->setNext(move(director));auto teamLeader = make_unique<TeamLeader>();teamLeader->setNext(move(manager));// 创建请求Request request;request.type = Request::Type::Leave;request.days = 7;// 提交请求teamLeader->handleRequest(&request);return 0;
}

相关文章:

C++设计模式-责任链模式:从基本介绍,内部原理、应用场景、使用方法,常见问题和解决方案进行深度解析

一、责任链模式的基本介绍 1.1 模式定义与核心思想 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;其核心思想是将请求的发送者和接收者解耦。通过创建一个由多个处理节点组成的链条&#xff0c;每个节点依次尝试处理请…...

工具介绍 | SafeLLMDeploy教程来了 保护本地LLM安全部署

SafeLLMDeploy&#xff1a;保护本地大语言模型安全部署的“守护者” 在AI技术飞速发展的今天&#xff0c;大语言模型&#xff08;LLM&#xff09;如GPT、DeepSeek等正以前所未有的方式改变着我们的工作和生活。然而&#xff0c;本地部署这些强大的AI系统在带来便利的同时&…...

我该怎么设置SVN客户端的认证信息?

设置SVN客户端的认证信息通常取决于您使用的SVN客户端类型&#xff08;命令行客户端或图形界面客户端&#xff09;。以下是一些常见SVN客户端的设置方法&#xff1a; 1. 使用命令行SVN客户端 对于命令行SVN客户端&#xff0c;您通常在执行SVN命令时直接输入用户名和密码&…...

机器学习-04-分类算法-03KNN算法案例

实验名称 K近邻算法实现葡萄酒分类 实验目的 通过未知品种的拥有13种成分的葡萄酒&#xff0c;应用KNN分类算法&#xff0c;完成葡萄酒分类&#xff1b; 熟悉K近邻算法应用的一般过程&#xff1b; 通过合理选择K值从而提高分类得到正确率&#xff1b; 实验背景 本例实验…...

AIP-213 通用组件

编号213原文链接AIP-213: Common components状态批准创建日期2018-08-17更新日期2018-08-17 根据AIP-215规定&#xff0c;除使用“通用组件”包之外&#xff0c;API必须是独立的。通用组件包是给多个API使用的。 通用组件包有两种类型&#xff1a; 组织特定的通用组件&#…...

Go语言-初学者日记(七):用 Go 写一个 RESTful API 服务!

&#x1f477; 实践是最好的学习方式&#xff01;这一篇我们将用 Go Gin 框架从零开始开发一个用户管理 API 服务。你将学到&#xff1a; 如何初始化项目并引入依赖如何组织目录结构如何用 Gin 实现 RESTful 接口如何通过 curl 测试 API进阶功能拓展建议 &#x1f9f0; 一、项…...

Java 搭建 MC 1.18.2 Forge 开发环境

推荐使用 IDEA 插件 Minecraft Development 进行创建项目 创建完成后即可进行 MOD 开发。 但是关于 1.18.2 的开发教程太少&#xff0c;因此自己研究了一套写法&#xff0c;写法并非是最优的但是是探索开发MOD中的一次笔记和记录 GITHUB: https://github.com/zimoyin/zhenfa…...

计算机网络知识点汇总与复习——(三)数据链路层

Preface 计算机网络是考研408基础综合中的一门课程&#xff0c;它的重要性不言而喻。然而&#xff0c;计算机网络的知识体系庞大且复杂&#xff0c;各类概念、协议和技术相互关联&#xff0c;让人在学习时容易迷失方向。在进行复习时&#xff0c;面对庞杂的的知识点&#xff0c…...

Verilog HDL 100道面试题及参考答案

目录 Verilog HDL 的四种基本逻辑值是什么? 关键字 reg 和 wire 的主要区别是什么? 解释阻塞赋值(=)与非阻塞赋值(<=)的区别,并举例说明。 如何声明一个双向端口(inout)? 位拼接操作符是什么?举例说明其用法。 拼接信号和常量 拼接常量和信号 重复拼接 以…...

内网(域)渗透测试流程和模拟测试day--5--Windows和Linux的提权

前景&#xff1a; 小知识&#xff1a; 认识一下土豆家族 是指一系列利用 Windows 系统漏洞实现提权的工具或方法&#xff0c;起源于 JuicyPotato。这些工具大多利用 COM 对象和服务中的权限提升漏洞&#xff0c;主要用于在 Windows 环境中从中低权限&#xff08;如普通用户&…...

主机和虚拟机间的网络通信

参考&#xff1a;Vmware虚拟机三种网络模式详解 - 林加欣 - 博客园 (cnblogs.com) 虚拟机配置 一般额外配置有线和无线网络 桥接模式 虚拟机和主机之间是同一个网络&#xff0c;用一根线连接了虚拟机和物理机的网卡,可以选择桥接的位置&#xff0c;默认情况下是自动桥接&…...

嵌入式Linux开发环境搭建,三种方式:虚拟机、物理机、WSL

目录 总结写前面一、Linux虚拟机1 安装VMware、ubuntu18.042 换源3 改中文4 中文输入法5 永不息屏6 设置 root 密码7 安装 terminator8 安装 htop&#xff08;升级版top&#xff09;9 安装 Vim10 静态IP-虚拟机ubuntu11 安装 ssh12 安装 MobaXterm &#xff08;SSH&#xff09;…...

说清楚单元测试

在团队中推行单元测试的时候,总是会被成员问一些问题: 这种测试无法测试数据库的SQL(或者是ORM)是否执行正确?这种测试好像没什么作用?关联的对象要怎么处理呢?…借由本篇,来全面看一看单元测试。 单元测试是软件开发中一种重要的测试方法,其核心目的是验证代码的最小…...

如何分析 jstat 统计来定位 GC?

全文目录&#xff1a; 开篇语前言摘要概述jstat 的核心命令与参数详解基本命令格式示例 jstat 输出解读主要字段含义 典型 GC 问题分析案例案例 1&#xff1a;年轻代 GC 过于频繁案例 2&#xff1a;老年代发生频繁 Full GC案例 3&#xff1a;元空间&#xff08;Metaspace&#…...

电商---part02 项目环境准备

1.虚拟机环境 可以通过VMWare来安装&#xff0c;但是通过VMWare安装大家经常会碰到网络ip连接问题&#xff0c;为了减少额外的环境因素影响&#xff0c;Docker内容会通过VirtualBox结合Vagrant来安装虚拟机。 VirtualBox官网&#xff1a;https://www.virtualbox.org/ Vagran…...

LabVIEW提升程序响应速度

LabVIEW 程序在不同计算机上的响应速度可能存在较大差异&#xff0c;这通常由两方面因素决定&#xff1a;计算机硬件性能和程序本身的优化程度。本文将分别从硬件配置对程序运行的影响以及代码优化方法进行详细分析&#xff0c;帮助提升 LabVIEW 程序的执行效率。 一、计算机硬…...

工业领域网络安全技术发展路径洞察报告发布 | FreeBuf咨询

工业网络安全已成为国家安全、经济稳定和社会运行的重要基石。随着工业互联网、智能制造和关键基础设施的数字化升级&#xff0c;工业系统的复杂性和互联性显著提升&#xff0c;针对工业领域的网络攻击朝着目标多样化、勒索攻击产业化、攻击技术持续升级的方向发展&#xff0c;…...

WPF 登录页面

效果 项目结构 LoginWindow.xaml <Window x:Class"PrismWpfApp.Views.LoginWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d"http://schemas.…...

【数学建模】动态规划算法(Dynamic Programming,简称DP)详解与应用

动态规划算法详解与应用 文章目录 动态规划算法详解与应用引言动态规划的基本概念动态规划的设计步骤经典动态规划问题1. 斐波那契数列2. 背包问题3. 最长公共子序列(LCS) 动态规划的优化技巧动态规划的应用领域总结 引言 动态规划(Dynamic Programming&#xff0c;简称DP)是一…...

leetcode-代码随想录-链表-移除链表元素

题目 链接&#xff1a;203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 …...

低成本训练垂直领域文娱大模型的技术路径

标题:低成本训练垂直领域文娱大模型的技术路径 内容:1.摘要 在文娱产业快速发展且对智能化需求日益增长的背景下&#xff0c;为降低垂直领域文娱大模型的训练成本&#xff0c;本研究旨在探索低成本训练的有效技术路径。采用对现有开源模型进行微调、利用轻量化模型架构以及优化…...

Spring Boot 3.4.3 基于 Caffeine 实现本地缓存

在现代企业级应用中,缓存是提升系统性能和响应速度的关键技术。通过减少数据库查询或复杂计算的频率,缓存可以显著优化用户体验。Spring Boot 3.4.3 提供了强大的缓存抽象支持,而 Caffeine 作为一款高性能的本地缓存库,因其优异的吞吐量和灵活的配置,成为许多开发者的首选…...

手机为电脑提供移动互联网络的3种方式

写作目的 在当今数字化时代,电脑已成为人们日常工作和生活中不可或缺的工具,而网络连接更是其核心功能之一。无论是处理工作任务、进行在线学习、还是享受娱乐资源,稳定的网络环境都是保障这些活动顺利开展的关键。然而,在实际使用过程中,电脑网络驱动故障时有发生,这可…...

论文阅读Diffusion Autoencoders: Toward a Meaningful and Decodable Representation

原文框架图&#xff1a; 官方代码&#xff1a; https://github.com/phizaz/diffae/blob/master/interpolate.ipynb 主要想记录一下模型的推理过程 &#xff1a; %load_ext autoreload %autoreload 2 from templates import * device cuda:1 conf ffhq256_autoenc() # pri…...

Python集合(五)

集合一&#xff1a; 跟字典一样&#xff0c;最大的特性就是唯一性&#xff0c;集合中的所有的元素都是独一无二的&#xff0c;并且还是无序的 创建集合 第一种&#xff1a; 第二种&#xff1a;集合推导式&#xff1a; 第三种&#xff1a;使用类型构造器&#xff1a; 集合是无…...

ISIS多区域配置

一、什么是ISIS多区域 ISIS&#xff08;Intermediate System to Intermediate System&#xff09;多区域是指网络被划分为多个逻辑区域&#xff08;Areas&#xff09;&#xff0c;不同区域之间通过特定的ISIS路由器&#xff08;Level-1-2&#xff09;进行路由交互。多区域设计提…...

2025-04-04 Unity 网络基础5——TCP分包与黏包

文章目录 1 分包与黏包2 解决方案2.1 数据接口2.2 定义消息2.3 NetManager2.4 分包、黏包处理 3 测试3.1 服务端3.2 客户端3.3 直接发送3.4 黏包发送3.5 分包发送3.6 分包、黏包发送3.7 其他 1 分包与黏包 ​ 分包、黏包指在网络通信中由于各种因素&#xff08;网络环境、API …...

Leetcode——150. 逆波兰表达式求值

题解一 思路 和上一期1047. 删除字符串中的所有相邻重复项没差太多&#xff0c;基本思想都一样&#xff0c;就是读取输入的数据&#xff0c;如果是运算符&#xff0c;就进行相应的运算&#xff0c;然后把运算结果压栈。 代码 class Solution {public int evalRPN(String[] …...

【Node】一文掌握 Express 的详细用法(Express 备忘速查)

文章目录 入门Hello Worldexpress -hexpress()RouterApplicationRequest属性方法 Response属性方法 示例RouterResponseRequestres.end()res.json([body])app.allapp.deleteapp.disable(name)app.disabled(name)app.engine(ext, callback)app.listen([port[, host[, backlog]]]…...

chromium魔改——绕过无限debugger反调试

在进行以下操作之前&#xff0c;请确保已完成之前文章中提到的 源码拉取及编译 部分。 如果已顺利完成相关配置&#xff0c;即可继续执行后续操作。 在浏览器中实现“无限 debugger”的反调试技术是一种常见的手段&#xff0c;用于防止他人通过开发者工具对网页进行调试或逆向…...