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

重温设计模式--职责链模式

文章目录

      • 职责链模式的详细介绍
      • C++ 代码示例
      • C++示例代码2

职责链模式的详细介绍

  1. 定义与概念
    职责链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它旨在将请求的发送者和多个接收者解耦,让多个对象都有机会处理请求,这些对象就像一条链一样依次传递请求,直到有一个对象能够处理该请求为止。如果某个对象不能处理请求,它会将请求转发给链上的下一个对象。

例如,在一个员工请假审批系统中,员工提交请假申请后,可能先由小组长审批,如果请假天数较多,小组长无法审批,就会将申请转交给部门经理审批,若部门经理权限也不够,还可能继续往上传递给更高层领导审批。这里的小组长、部门经理、高层领导等就构成了一条职责链,每个角色都是链上的一环,根据自己的审批权限来决定是否处理该请假申请这个请求。

  1. 角色构成及职责

    • 抽象处理者(Handler):它定义了一个处理请求的接口,通常包含一个抽象的处理请求方法以及设置下一个处理者的方法。这个抽象类是整个职责链的基础,所有具体的处理者类都要继承自它。例如,在上述请假审批示例中,抽象处理者可以定义一个抽象的“审批请求”方法和“设置下一个审批者”的方法,无论是小组长还是部门经理等具体审批角色对应的类都要遵循这个统一的接口规范。
    • 具体处理者(ConcreteHandler):是抽象处理者的子类,实现了处理请求的具体逻辑。每个具体处理者会判断自己是否能够处理当前请求,如果可以,就进行处理;如果不行,就将请求传递给下一个处理者(通过调用设置好的下一个处理者对应的处理请求方法)。比如小组长这个具体处理者,会根据自己能审批的请假天数范围来判断是否处理员工的请假申请,若超出范围就把申请转交给部门经理这个下一个处理者。
    • 请求(Request):这是需要在职责链中传递并被处理的对象,它包含了与请求相关的各种信息,例如请假申请中的请假天数、请假事由等内容。
      在这里插入图片描述
  2. 优点

    • 降低耦合度:请求的发送者不需要知道具体是哪个对象来处理请求,它只需要将请求发送到职责链的起始端即可,而各个具体处理者之间也只是通过链的方式依次传递请求,相互之间的依赖关系比较松散,便于系统的维护和扩展。
    • 增强灵活性:可以动态地增加、删除或者重新排列职责链上的处理者,比如在请假审批系统中,如果公司组织结构调整,增加了新的管理层级或者调整了审批权限,只需要相应地修改或添加具体处理者类以及调整它们在链上的顺序就可以适应变化,而不需要大规模改动整个系统的其他部分。
    • 便于分工协作:不同的具体处理者可以专注于处理自己职责范围内的请求,符合单一职责原则,有利于代码的编写、测试以及后续的维护工作。
  3. 缺点

    • 可能导致性能问题:如果职责链比较长,而且每个请求都需要遍历较长的链才能找到合适的处理者,可能会消耗较多的时间和资源,特别是在对性能要求较高的场景下,这一点需要注意并合理优化。
    • 调试难度增加:由于请求在多个对象之间传递,当出现问题时,确定是哪个环节的处理者出现故障或者错误的处理逻辑相对复杂一些,不利于快速定位和解决问题。
  4. 应用场景

    • 审批流程:如前面提到的员工请假审批、费用报销审批等各种涉及多层级审批的场景,不同层级的审批人员构成职责链,根据审批权限来处理请求。
    • 事件处理系统:在图形用户界面开发中,比如鼠标点击事件、键盘按键事件等,不同的控件或者组件可以按照一定的顺序构成职责链,根据各自的功能和逻辑来判断是否处理这些事件,比如先由按钮控件判断是否点击在自己范围内,如果不是再由父容器等继续判断处理。
    • 客户服务系统:客户提出的问题按照问题的类型、难度等可以在不同的客服人员或者部门之间传递,例如一线客服先尝试解决简单问题,解决不了就转交给专业技术部门等,形成一条处理客户问题的职责链。

C++ 代码示例

以下是一个简单的模拟请假审批的 C++ 代码示例来体现职责链模式:

#include <iostream>
#include <string>// 请求类,这里模拟请假申请,包含请假天数和请假事由
class LeaveRequest {
public:LeaveRequest(int days, const std::string& reason) : m_days(days), m_reason(reason) {}int getDays() const { return m_days; }std::string getReason() const { return m_reason; }private:int m_days;std::string m_reason;
};// 抽象处理者类,定义处理请求的接口以及设置下一个处理者的方法
class Handler {
public:Handler() : m_nextHandler(nullptr) {}virtual ~Handler() = default;void setNextHandler(Handler* next) { m_nextHandler = next; }virtual void handleRequest(LeaveRequest& request) = 0;protected:Handler* m_nextHandler;
};// 具体处理者 - 小组长类
class TeamLeader : public Handler {
public:void handleRequest(LeaveRequest& request) override {if (request.getDays() <= 2) {std::cout << "Team leader approved the leave request for " << request.getReason() << ". Days: " << request.getDays() << std::endl;} else if (m_nextHandler!= nullptr) {m_nextHandler->handleRequest(request);}}
};// 具体处理者 - 部门经理类
class DepartmentManager : public Handler {
public:void handleRequest(LeaveRequest& request) override {if (request.getDays() <= 5) {std::cout << "Department manager approved the leave request for " << request.getReason() << ". Days: " << request.getDays() << std::endl;} else if (m_nextHandler!= nullptr) {m_nextHandler->handleRequest(request);}}
};// 具体处理者 - 总经理类
class GeneralManager : public Handler {
public:void handleRequest(LeaveRequest& request) override {std::cout << "General manager approved the leave request for " << request.getReason() << ". Days: " << request.getDays() << std::endl;}
};int main() {LeaveRequest request1(1, "Personal affairs");LeaveRequest request2(4, "Sick leave");LeaveRequest request3(8, "Family trip");TeamLeader teamLeader;DepartmentManager departmentManager;GeneralManager generalManager;teamLeader.setNextHandler(&departmentManager);departmentManager.setNextHandler(&generalManager);teamLeader.handleRequest(request1);teamLeader.handleRequest(request2);teamLeader.handleRequest(request3);return 0;
}

在上述代码中:

  • LeaveRequest 类作为请求对象,封装了请假天数和请假事由等信息。
  • Handler 类是抽象处理者,定义了 handleRequest 方法用于处理请求以及 setNextHandler 方法来设置下一个处理者。
  • TeamLeaderDepartmentManagerGeneralManager 分别是具体的处理者类,它们继承自 Handler 类,在 handleRequest 方法中根据自己的审批权限(这里以请假天数衡量)来决定是处理请求还是将请求传递给下一个处理者。
  • main 函数中,创建了不同的请求对象以及各个具体处理者对象,并将它们连接成职责链(通过 setNextHandler 方法),然后将请求依次发送到职责链的起始端(这里是小组长),由职责链上的处理者根据自身规则来处理请求。

C++示例代码2

#include<iostream>
#include<string>
using namespace std;
//请求
class request
{
public:string type;//类型int count;//数量string content;//内容
public:request(string m_type, int len ,string m_content):type(m_type),count(len),content(m_content){}
};
//抽象管理类
class Manger
{
protected:string m_name;Manger *super;
public:Manger(string name):m_name(name){}virtual void setsuper(Manger *m_super){super = m_super;}virtual void requestapplication(request m_request){}
};
//经理
class jingli:public Manger
{
public:jingli(string name):Manger(name){}void requestapplication(request m_request){if(m_request.type=="请假" && m_request.count<3){cout<<m_name<<": "<<m_request.content<<"数量:"<<m_request.count<<" 批准"<<endl;}else{super->requestapplication(m_request);}}
};
//主管
class zhuguan:public Manger
{
public:zhuguan(string name):Manger(name){}void requestapplication(request m_request){if(m_request.type=="请假" && m_request.count<5){cout<<m_name<<": "<<m_request.content<<"数量:"<<m_request.count<<" 批准"<<endl;}else{super->requestapplication(m_request);}}
};
//总经理
class zongjingli:public Manger
{
public:zongjingli(string name):Manger(name){}void requestapplication(request m_request){if(m_request.type=="请假" && m_request.count<10){cout<<m_name<<": "<<m_request.content<<"数量:"<<m_request.count<<" 批准"<<endl;}else{cout<<m_name<<": "<<m_request.content<<"数量:"<<m_request.count<<" 不批准"<<endl;}}
};
int main()
{request *myrequest = new request("请假" ,6,"小明请假");jingli *m_jingli = new jingli("经理");zhuguan*m_zhuguan = new zhuguan("主管");zongjingli *m_zongjingli = new zongjingli("总经理");m_jingli->setsuper(m_zhuguan);m_zhuguan->setsuper(m_zongjingli);m_jingli->requestapplication(*myrequest);myrequest->count=100;cout<<endl;m_jingli->requestapplication(*myrequest);myrequest->count=1;cout<<endl;m_jingli->requestapplication(*myrequest);return 0;
}

相关文章:

重温设计模式--职责链模式

文章目录 职责链模式的详细介绍C 代码示例C示例代码2 职责链模式的详细介绍 定义与概念 职责链模式&#xff08;Chain of Responsibility Pattern&#xff09;是一种行为型设计模式&#xff0c;它旨在将请求的发送者和多个接收者解耦&#xff0c;让多个对象都有机会处理请求&a…...

git冲突解决

git冲突解决 最近遇到了一次git冲突的问题 起因是因为最近公司数据推送部分重构&#xff0c;负责重构的同事就改动了我的一小部分推送的代码&#xff0c;然后等我开发完合并到远程master的时候&#xff0c;报了merge冲突。我对于git工具确实不是很熟练&#xff0c;只是学习了…...

Java学习笔记(14)--面向对象编程

面向对象基础 学习资料来自多态 - Java教程 - 廖雪峰的官方网站 目录 面向对象基础 Override 多态 举个例子 覆写Object方法 调用super final 练习 小结 Override 在继承关系中&#xff0c;子类如果定义了一个与父类方法签名完全相同的方法&#xff0c;被称为覆写&…...

《Swift 字面量》

《Swift 字面量》 介绍 在 Swift 编程语言中&#xff0c;字面量是一种表示源代码中固定值的表达方式。字面量可以直接表示数字、字符串、布尔值等基本数据类型&#xff0c;为编程提供了简洁和直观的方式。Swift 支持多种类型的字面量&#xff0c;包括整数字面量、浮点数字面量…...

数据库 SQL 常用语句全解析

数据库 SQL 常用语句全解析 在数据库领域&#xff0c;SQL&#xff08;Structured Query Language&#xff09;作为标准语言&#xff0c;掌控着数据的查询、插入、更新与删除等关键操作。无论是新手入门数据库&#xff0c;还是经验丰富的开发者日常工作&#xff0c;熟练掌握 SQ…...

SQLite 命令

关于《SQLite 命令》的文章&#xff0c;我可以为您概述一些关键点。SQLite是一个轻量级的数据库管理系统&#xff0c;它被广泛用于各种应用程序中。SQLite命令主要分为两类&#xff1a;一类是SQL命令&#xff0c;另一类是SQLite特定的点命令。 SQL命令&#xff1a;这些命令用于…...

本地如何启动casdoor

1、下载代码 GitHub - casdoor/casdoor at v1.777.0 下载对应tag的代码&#xff0c;我这里选择的时v1.777.0版本 通过网盘分享的文件&#xff1a;casdoor-1.777.0.zip 链接: https://pan.baidu.com/s/1fPNqyJYeyfZnem_LtEc0hw 提取码: avpd 2、启动后端 1、使用goland编译…...

目标检测-R-CNN

R-CNN在2014年被提出&#xff0c;算法流程可以概括如下&#xff1a; 候选区域生成&#xff1a;利用选择性搜索(selective search)方法找出图片中可能存在目标的候选区域(region proposal) CNN网络提取特征&#xff1a;对候选区域进行特征提取(可以使用AlexNet、VGG等网络) 目…...

【持续更新】Github实用命令

Intro 最近高强度使用github&#xff0c;遂小计于此作为备忘。 Basic github是一个代码管理软件&#xff0c;能够track文件变动并且管理版本&#xff0c;是当代coding必不可少的工具。当你安装好github在本地以后&#xff0c;你可以通过以下命令初始化当前文件夹&#xff08…...

docker 容器的基本使用

docker 容器 一、docker是什么&#xff1f; 软件的打包技术&#xff0c;就是将算乱的多个文件打包为一个整体&#xff0c;打包技术在没有docker容器之前&#xff0c;一直是有这种需求的&#xff0c;比如上节课我把我安装的虚拟机给你们打包了&#xff0c;前面的这种打包方式是…...

css让按钮放在最右侧

要将 el-button 按钮放在最右侧&#xff0c;可以使用多种方法&#xff0c;具体取决于使用的布局方式和样式库。以下是几种常见的解决方案&#xff1a; 方法 1&#xff1a;使用 CSS Flexbox Flexbox 是一种非常灵活的布局方式&#xff0c;可以轻松实现水平或垂直对齐。你可以将…...

8K+Red+Raw+ProRes422分享5个影视级视频素材网站

Hello&#xff0c;大家好&#xff0c;我是后期圈&#xff01; 在视频创作中&#xff0c;电影级的视频素材能够为作品增添专业质感&#xff0c;让画面更具冲击力。无论是广告、电影短片&#xff0c;还是品牌宣传&#xff0c;高质量的视频素材都是不可或缺的资源。然而&#xff…...

Linux网络——UDP的运用

Linux网络——UDP的运用 文章目录 Linux网络——UDP的运用一、引入二、服务端实现2.1 创建socket套接字2.2 指定网络接口并bind2.3 接收数据并处理2.4 整体代码2.5 IP的绑定的细节 三、用户端实现3.1 创建套接字3.2 指定网络接口3.3 发生数据并接收3.4 绑定问题 四、代码五、UD…...

项目亮点案例

其实对我来说是日常操作&#xff0c;但是如果在面试的时候面试者能把日常的事情总结好发出来&#xff0c;其实足矣。 想让别人认同项目&#xff0c;选取的示例需要包含以下要素&#xff1a; 亮点项目四要素&#xff1a;明确的目标&#xff0c;问题点&#xff0c;解决方法和结果…...

Retrofit源码分析:动态代理获取Api接口实例,解析注解生成request,线程切换

目录 一&#xff0c;Retrofit的基本使用 1.定义api接口 2.创建Retrofit实例 3.获取api接口实例发起请求 二&#xff0c;静态代理和动态代理 1&#xff0c;静态代理 2&#xff0c;动态代理 三&#xff0c;动态代理获取Api接口实例 四&#xff0c;解析接口方法注解&…...

范德蒙矩阵(Vandermonde 矩阵)简介:意义、用途及编程应用

参考&#xff1a; Introduction to Applied Linear Algebra – Vectors, Matrices, and Least Squares Stephen Boyd and Lieven Vandenberghe 书的网站: https://web.stanford.edu/~boyd/vmls/ Vandermonde 矩阵简介&#xff1a;意义、用途及编程应用 在数学和计算科学中&a…...

【中标麒麟服务器操作系统实例分享】java应用DNS解析异常分析及处理

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer.kylinos.cn 文档中心&#xff1a;https://document.kylinos.cn 情况描述 中标麒麟服务器操作系统V7运行在 ARM…...

网安瞭望台第17期:Rockstar 2FA 故障催生 FlowerStorm 钓鱼即服务扩张现象剖析

国内外要闻 Rockstar 2FA 故障催生 FlowerStorm 钓鱼即服务扩张现象剖析 在网络安全的复杂战场中&#xff0c;近期出现了一个值得关注的动态&#xff1a;名为 Rockstar 2FA 的钓鱼即服务&#xff08;PhaaS&#xff09;工具包遭遇变故&#xff0c;意外推动了另一个新生服务 Flo…...

玩转OCR | 探索腾讯云智能结构化识别新境界

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ 玩转OCR 腾讯云智能结构化识别产品介绍服务应用产品特征行业案例总结 腾讯云智能结构化识别 腾讯云智能结构化OCR产品分为基础版与高级版&am…...

idea2024创建JavaWeb项目以及配置Tomcat详解

今天呢&#xff0c;博主的学习进度也是步入了JavaWeb&#xff0c;目前正在逐步杨帆旗航&#xff0c;迎接全新的狂潮海浪。 那么接下来就给大家出一期有关JavaWeb的配置教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数&#xff0c;对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

dify打造数据可视化图表

一、概述 在日常工作和学习中&#xff0c;我们经常需要和数据打交道。无论是分析报告、项目展示&#xff0c;还是简单的数据洞察&#xff0c;一个清晰直观的图表&#xff0c;往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server&#xff0c;由蚂蚁集团 AntV 团队…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...