职责链模式(Chain of Responsibility)详解

一、核心概念

职责链模式将请求的发送者和接收者解耦,使多个对象都有机会处理请求。这些对象连接成一条链,请求沿着链传递,直到有一个对象处理它为止。该模式允许动态调整处理者的顺序或组合,增强系统灵活性。

核心组件

  1. 抽象处理者(Handler):定义处理请求的接口,包含对下一个处理者的引用。
  2. 具体处理者(Concrete Handler):实现处理请求的方法,决定是否处理请求或将其传递给下一个处理者。
  3. 客户端(Client):将请求发送到链的起始处理者。
二、代码示例:员工请假审批系统

场景:员工请假需要不同层级的领导审批(组长→经理→总监),根据请假天数自动选择审批者。

#include <iostream>
#include <memory>// 请假请求
class LeaveRequest {
private:int days;std::string name;public:LeaveRequest(const std::string& name, int days) : name(name), days(days) {}int getDays() const { return days; }std::string getName() const { return name; }
};// 抽象处理者:领导
class Leader {
protected:std::shared_ptr<Leader> nextLeader;  // 指向下一个处理者public:virtual void setNextLeader(std::shared_ptr<Leader> leader) {nextLeader = leader;}virtual void handleRequest(const LeaveRequest& request) = 0;virtual ~Leader() = default;
};// 具体处理者:组长
class TeamLeader : public Leader {
public:void handleRequest(const LeaveRequest& request) override {if (request.getDays() <= 3) {std::cout << "组长批准" << request.getName() << "请假" << request.getDays() << "天" << std::endl;} else if (nextLeader) {std::cout << "组长无法处理,转交上级..." << std::endl;nextLeader->handleRequest(request);} else {std::cout << "请假天数过长,无人处理" << std::endl;}}
};// 具体处理者:经理
class Manager : public Leader {
public:void handleRequest(const LeaveRequest& request) override {if (request.getDays() <= 7) {std::cout << "经理批准" << request.getName() << "请假" << request.getDays() << "天" << std::endl;} else if (nextLeader) {std::cout << "经理无法处理,转交上级..." << std::endl;nextLeader->handleRequest(request);} else {std::cout << "请假天数过长,无人处理" << std::endl;}}
};// 具体处理者:总监
class Director : public Leader {
public:void handleRequest(const LeaveRequest& request) override {if (request.getDays() <= 15) {std::cout << "总监批准" << request.getName() << "请假" << request.getDays() << "天" << std::endl;} else {std::cout << "请假天数超过15天,拒绝批准" << std::endl;}}
};// 客户端代码
int main() {// 创建处理者auto teamLeader = std::make_shared<TeamLeader>();auto manager = std::make_shared<Manager>();auto director = std::make_shared<Director>();// 构建责任链teamLeader->setNextLeader(manager);manager->setNextLeader(director);// 提交请假请求LeaveRequest request1("张三", 2);teamLeader->handleRequest(request1);LeaveRequest request2("李四", 5);teamLeader->handleRequest(request2);LeaveRequest request3("王五", 10);teamLeader->handleRequest(request3);LeaveRequest request4("赵六", 20);teamLeader->handleRequest(request4);return 0;
}
三、职责链模式的优势
  1. 解耦发送者和接收者

    • 请求者无需知道哪个对象处理请求,只需将请求发送到链上。
  2. 动态组合处理者

    • 可在运行时动态调整处理者的顺序或组成。
  3. 简化对象职责

    • 每个处理者只需关注自己的职责,无需关心整条链的结构。
  4. 增强可扩展性

    • 新增处理者只需实现接口并加入链中,无需修改现有代码。
四、实现变种
  1. 纯职责链 vs 不纯职责链

    • 纯职责链:每个处理者要么处理请求,要么完全不处理(如示例)。
    • 不纯职责链:处理者可部分处理请求后继续传递(如日志过滤)。
  2. 动态链构建

    • 通过配置文件或工厂动态构建责任链,适应不同场景。
  3. 并行链处理

    • 多个处理者同时处理请求,返回首个成功的结果(如负载均衡)。
五、适用场景
  1. 多级审批系统

    • 如请假、报销等流程,根据金额或权限自动分配审批人。
  2. 事件处理系统

    • 如GUI事件传递(按钮点击→容器→窗口)。
  3. 日志过滤系统

    • 根据日志级别(INFO→WARN→ERROR)选择处理方式。
  4. 请求拦截器

    • 如Web应用中的过滤器链(身份验证→日志记录→权限检查)。
六、注意事项
  1. 链的完整性

    • 确保链的末端有默认处理者,避免请求无人处理。
  2. 性能问题

    • 过长的链可能影响性能,需控制链的长度。
  3. 调试难度

    • 链的动态性可能导致调试困难,需添加适当的日志。
  4. 与状态模式的区别

    • 职责链模式中处理者可自由决定是否传递请求;状态模式中状态转移由上下文控制。

职责链模式通过将请求处理者组织成链,实现了请求发送者与接收者的解耦,使系统更具灵活性和可维护性。在需要动态处理请求或多级处理的场景中,该模式尤为适用。

中介者模式(Mediator Pattern)详解

一、核心概念

中介者模式通过一个中介对象来封装一系列对象间的交互,使各对象无需显式引用彼此,从而降低耦合度。中介者负责协调对象间的通信,所有交互都通过中介者进行,而非对象直接调用。

核心组件

  1. 抽象中介者(Mediator):定义协调对象交互的接口。
  2. 具体中介者(Concrete Mediator):实现中介者接口,维护对象引用并处理交互逻辑。
  3. 抽象同事类(Colleague):定义同事对象的公共接口,持有中介者引用。
  4. 具体同事类(Concrete Colleague):实现抽象同事类,通过中介者与其他同事通信。

没有使用中介模式前是网状结构,关系混乱

现在改为辐射状,变为多对一

二、代码示例:机场塔台调度系统

场景:飞机降落和起飞需要塔台协调,避免跑道冲突。飞机(同事)不直接通信,而是通过塔台(中介者)调度。

#include <iostream>
#include <string>
#include <memory>
#include <vector>// 前向声明
class Tower;// 抽象同事类:飞机
class Aircraft {
protected:Tower* tower;std::string flightNumber;public:Aircraft(Tower* tower, const std::string& flightNumber) : tower(tower), flightNumber(flightNumber) {}virtual void requestLanding() = 0;virtual void confirmLanding() = 0;virtual std::string getFlightNumber() const = 0;virtual ~Aircraft() = default;
};// 抽象中介者:塔台
class Tower {
public:virtual void registerAircraft(Aircraft* aircraft) = 0;virtual void handleLandingRequest(Aircraft* aircraft) = 0;virtual void clearRunway() = 0;virtual ~Tower() = default;
};// 具体同事类:客机
class PassengerAircraft : public Aircraft {
public:using Aircraft::Aircraft;  // 继承构造函数void requestLanding() override {std::cout << "[" << flightNumber << "] 请求降落" << std::endl;tower->handleLandingRequest(this);}void confirmLanding() override {std::cout << "[" << flightNumber << "] 确认降落,跑道清空" << std::endl;}std::string getFlightNumber() const override { return flightNumber; }
};// 具体同事类:货机
class CargoAircraft : public Aircraft {
public:using Aircraft::Aircraft;  // 继承构造函数void requestLanding() override {std::cout << "[" << flightNumber << "] 请求降落" << std::endl;tower->handleLandingRequest(this);}void confirmLanding() override {std::cout << "[" << flightNumber << "] 确认降落,跑道清空" << std::endl;}std::string getFlightNumber() const override { return flightNumber; }
};// 具体中介者:控制塔台
class ControlTower : public Tower {
private:std::vector<Aircraft*> aircrafts;bool runwayAvailable = true;public:void registerAircraft(Aircraft* aircraft) override {aircrafts.push_back(aircraft);std::cout << "塔台已注册航班: " << aircraft->getFlightNumber() << std::endl;}void handleLandingRequest(Aircraft* aircraft) override {if (runwayAvailable) {runwayAvailable = false;std::cout << "塔台: 跑道可用," << aircraft->getFlightNumber() << " 可以降落" << std::endl;aircraft->confirmLanding();} else {std::cout << "塔台: 跑道繁忙," << aircraft->getFlightNumber() << " 请等待" << std::endl;}}void clearRunway() override {runwayAvailable = true;std::cout << "塔台: 跑道已清空,可以接受新降落请求" << std::endl;}
};// 客户端代码
int main() {auto tower = std::make_unique<ControlTower>();auto plane1 = std::make_unique<PassengerAircraft>(tower.get(), "CA1234");auto plane2 = std::make_unique<CargoAircraft>(tower.get(), "CZ5678");auto plane3 = std::make_unique<PassengerAircraft>(tower.get(), "MU9012");tower->registerAircraft(plane1.get());tower->registerAircraft(plane2.get());tower->registerAircraft(plane3.get());// 模拟多个飞机同时请求降落plane1->requestLanding();plane2->requestLanding();plane3->requestLanding();// 跑道清空后再次请求tower->clearRunway();plane2->requestLanding();return 0;
}
三、中介者模式的优势
  1. 降低耦合度

    • 对象间无需直接引用,所有交互通过中介者,减少依赖。
  2. 集中控制交互

    • 中介者作为交互中心,便于统一管理和修改交互逻辑。
  3. 增强可扩展性

    • 新增同事或修改交互逻辑只需调整中介者,无需修改所有同事类。
  4. 简化对象设计

    • 同事类只需关注自身业务逻辑,无需处理复杂的交互关系。
四、实现变种
  1. 事件总线(Event Bus)

    • 中介者维护事件队列,同事通过发布/订阅机制通信(如Guava EventBus)。
  2. MVC模式中的Controller

    • Controller作为View和Model的中介者,处理两者间的交互。
  3. 分布式系统中的消息队列

    • 如RabbitMQ、Kafka作为服务间的中介者,实现解耦通信。
五、适用场景
  1. 对象间交互复杂

    • 如GUI组件间的交互(按钮、文本框、下拉菜单)。
  2. 网状结构转星型结构

    • 将多对多关系转化为一对多关系,如社交网络中的好友关系。
  3. 系统模块间松耦合

    • 如电商系统中订单、库存、支付模块的交互。
  4. 需要集中控制的场景

    • 如多人游戏中的房间管理、交通调度系统。
六、注意事项
  1. 中介者复杂度

    • 中介者可能变得过于庞大,需合理拆分功能或采用分层中介者。
  2. 单点故障风险

    • 中介者作为核心组件,若出现故障可能影响整个系统。
  3. 性能开销

    • 所有交互通过中介者中转,可能引入性能瓶颈。
  4. 与观察者模式的区别

    • 中介者模式中同事对象依赖中介者;观察者模式中观察者与被观察对象松耦合。

中介者模式通过引入中介对象,将复杂的对象间交互集中管理,降低了系统耦合度,提高了可维护性。在需要控制对象间直接通信的场景中,该模式尤为有效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/87433.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/87433.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/87433.shtml

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

相关文章

左神算法之Zigzag方式打印矩阵

目录 Zigzag方式打印矩阵1. 题目2. 解释3. 思路4. 代码5. 总结 Zigzag方式打印矩阵 1. 题目 用zigzag的方式打印矩阵&#xff0c;比如下面的矩阵&#xff1a; 0 1 2 3 4 5 6 7 8 9 10 11打印顺序为&#xff1a;0 1 4 8 5 2 3 6 9 10 7 11 2. 解释 Zigzag打印矩阵是指按照…

【前端批量下载图片,并打包成压缩包下载】

一、需求说明 我现在有个需求&#xff1a; 1.列表中有个下载按钮&#xff0c;点击下载&#xff0c;将列表中所有的图片打成压缩包&#xff0c;并下载 2.效果演示点击查看效果 最终效果&#xff1a; 二、安装下载插件 实现此功能需要两个插件&#xff1a;jszip、file-saver …

NV133NV137美光固态闪存NV147NV148

NV133NV137美光固态闪存NV147NV148 美光固态闪存技术矩阵深度解析&#xff1a;NV133至NV148的全面较量 一、性能参数&#xff1a;数据高速公路的“车速”比拼 读写速度&#xff1a;从“乡间小道”到“高铁动脉” 美光NV系列固态闪存的核心竞争力在于其读写速度的跃升。以NV15…

从LLM到WM:大语言模型如何进化成具身世界模型?

1.引言这学期在方老师开设的《机器人大模型基础和前沿》选修课上接触并学习了具身智能方面的相关知识。作为交互组的组长&#xff0c;我和组员们在幻尔机器狗的功能开发上有切身的实践与探索&#xff0c;在张江具身智能大会上&#xff0c;也见识到了前沿的技术和行业的发展现状…

第十六届蓝桥杯C++B组国赛题解+复盘总结

文章目录 写在前面1、新型锁2、互质藏卡3、数字轮盘4、斐波那契字符串5、项链排列6、蓝桥星数字7、翻倍8、近似回文字符串9、子串去重10、涂格子 写在前面 打了三年&#xff0c;第十六届是我最后一次参加了&#xff0c;终于如愿以偿国一啦。 这场的大多题目都补了&#xff0c;…

【TTS】2024-2025年主流开源TTS模型的综合对比分析

以下是针对2024-2025年主流开源与商用TTS模型的综合技术选型分析&#xff0c;结合GitHub热度、功能特性、部署成本及中文支持等核心维度进行对比&#xff0c;并附详细实践建议。 一、开源TTS模型对比&#xff08;2024-2025年主流方案&#xff09; 模型名称开源/厂商克隆支持中…

redis延时双删,为什么第一次删除

Redis延时双删策略中第一次删除的作用 在缓存与数据库一致性方案中&#xff0c;"延时双删"&#xff08;Delayed Double-Delete&#xff09;是一种经典策略&#xff0c;其核心流程如下&#xff1a; 第一次删除&#xff1a;更新数据库前&#xff0c;先删除缓存 更新数…

深度学习1(深度学习和机器学习的区别,神经网络)

深度学习和机器学习的区别 深度学习和机器学习都是人工智能&#xff08;AI&#xff09;的重要分支&#xff0c;但它们在方法、应用场景和技术细节上有显著区别。 机器学习通过算法让计算机从数据中学习规律&#xff0c;并做出预测或决策。核心是特征工程&#xff08;人工提取数…

这才叫窗口查询!TDEngine官方文档没讲透的实战玩法

第1章&#xff1a;你不知道的TDEngine窗口查询——开局就不简单 先别急着翻白眼&#xff0c;提到时间窗口查询&#xff0c;可能你脑子里立马浮现的就是那些常规套路&#xff1a;GROUP BY time_interval、FIRST()、LAST()&#xff0c;再加上点AVG()和MAX()&#xff0c;一锅端。…

Day50 预训练模型+CBAM模块

目录 一、resnet结构解析 二、CBAM放置位置的思考 三、针对预训练模型的训练策略 a.差异化学习率 b.三阶段式解冻与微调 (Progressive Unfreezing) 四、尝试对vgg16cbam进行微调策略 是否可以对于预训练模型增加模块来优化其效果&#xff0c;这里会遇到一个问题&#xff…

快速说一下TDD BDD DDD

基本概念 TDD&#xff08;测试驱动开发&#xff09;、BDD&#xff08;行为驱动开发&#xff09;和 DDD&#xff08;领域驱动设计&#xff09;是软件开发领域中几个重要的概念&#xff0c;它们各自有着独特的侧重点与应用场景&#xff0c;以下为你详细介绍&#xff1a; 测试驱…

浅析基于深度学习算法的英文OCR技术工作原理及其应用场景

在数字化信息飞速发展的当下&#xff0c;大量的文本信息以各种形式存在&#xff0c;从传统的纸质文档到电子图片中的文字内容。如何高效地将这些非结构化的文本转化为计算机能够理解和处理的格式&#xff0c;成为了提高信息处理效率的关键。英文 OCR&#xff08;Optical Charac…

AI时代SEO关键词策略

内容概要 在人工智能&#xff08;AI&#xff09;驱动的新时代&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;关键词策略正迎来颠覆性变革。本篇文章将系统解析AI技术如何重塑关键词研究、内容优化及流量提升的全过程&#xff0c;帮助企业实现高效可持续的在线曝光。通过…

免费一键自动化申请、续期、部署、监控所有 SSL/TLS 证书,ALLinSSL开源免费的 SSL 证书自动化管理平台

目录 一、前言二、ALLinSSL 简介亮点核心功能 三、操作步骤部署安装授权DNS服务商授权你的主机服务器自动化部署ssl测试自动申请ssl证书 一、前言 SSL证书是每个网站必备的&#xff0c;但是现在的免费的ssl证书有效期是3个月&#xff0c;以后CA/B Forum 调整 SSL 证书最长有效期…

如何高效清理C盘、释放存储空间,让电脑不再卡顿。

以下是针对Windows系统的C盘深度清理全攻略&#xff0c;包含系统级优化和进阶操作&#xff0c;可释放30%-70%的冗余空间&#xff1a; 一、系统自带工具快速清理&#xff08;5分钟见效&#xff09; 磁盘清理工具 按WinR → 输入cleanmgr → 选择C盘重点勾选&#xff1a; ✅ Wind…

AI 如何批量提取 Word 表格中的字段数据到 Excel 中?

在日常工作中&#xff0c;我们经常会接触到大量 Word 表格——学生登记表、客户信息表、报名信息表……这些表格数据往往格式不一&#xff0c;但有一个共同的需求&#xff1a; 从中提取出“字段-值”结构&#xff0c;统一导入 Excel&#xff0c;方便后续分析处理。 传统手工操作…

github代码中遇到的问题-解决方案

下面内容介绍的是我个人在复现github代码遇到的一些问题&#xff0c;如果也可以帮到你&#xff0c;请点个关注吧~ 1.我的项目位置在D盘&#xff0c;但是为什么下面终端的位置在E盘 -》cd /d D:\Users\xxxx&#xff08;后面的xxxx是你具体的文档位置&#xff09; 2.怎么知道我…

使用Visual Studio 2022创建CUDA编程项目

要在 Visual Studio 2022 中开发 CUDA 程序,需要进行环境配置并了解基本开发流程。以下是详细步骤: 环境准备 安装 Visual Studio 2022 下载并安装 Visual Studio 2022(社区版或专业版均可)。安装时勾选 “使用 C++ 的桌面开发” 工作负载。确保安装 “C++ CMake 工具” …

Java测试题一

1.基本数据类型有哪些&#xff1f; 基本数据类型有8个&#xff1a;整数&#xff1a;byte、int、long、short。 浮点型&#xff1a;float、double。 布尔型boolean。 字符型&#xff1a;char 2.下列代码的输出是什么&#xff1f;为什么&#xff1f; public static void ma…

使用 Flask 构建基于 Dify 的企业资金投向与客户分类评估系统

使用 Flask 构建基于 Dify 的企业资金投向与客户分类评估系统 前言一、&#x1f9e9; 技术栈二、&#x1f4e6; 项目结构概览三、 &#x1f527; 核心功能模块说明1 配置参数2 请求封装函数✅ 功能说明&#xff1a; 3 Prompt 构造函数4 Flask 路由定义&#x1f3e0; 首页路由 /…