重温设计模式--职责链模式
文章目录
- 职责链模式的详细介绍
- C++ 代码示例
- C++示例代码2
职责链模式的详细介绍
- 定义与概念
职责链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它旨在将请求的发送者和多个接收者解耦,让多个对象都有机会处理请求,这些对象就像一条链一样依次传递请求,直到有一个对象能够处理该请求为止。如果某个对象不能处理请求,它会将请求转发给链上的下一个对象。
例如,在一个员工请假审批系统中,员工提交请假申请后,可能先由小组长审批,如果请假天数较多,小组长无法审批,就会将申请转交给部门经理审批,若部门经理权限也不够,还可能继续往上传递给更高层领导审批。这里的小组长、部门经理、高层领导等就构成了一条职责链,每个角色都是链上的一环,根据自己的审批权限来决定是否处理该请假申请这个请求。
-
角色构成及职责
- 抽象处理者(Handler):它定义了一个处理请求的接口,通常包含一个抽象的处理请求方法以及设置下一个处理者的方法。这个抽象类是整个职责链的基础,所有具体的处理者类都要继承自它。例如,在上述请假审批示例中,抽象处理者可以定义一个抽象的“审批请求”方法和“设置下一个审批者”的方法,无论是小组长还是部门经理等具体审批角色对应的类都要遵循这个统一的接口规范。
- 具体处理者(ConcreteHandler):是抽象处理者的子类,实现了处理请求的具体逻辑。每个具体处理者会判断自己是否能够处理当前请求,如果可以,就进行处理;如果不行,就将请求传递给下一个处理者(通过调用设置好的下一个处理者对应的处理请求方法)。比如小组长这个具体处理者,会根据自己能审批的请假天数范围来判断是否处理员工的请假申请,若超出范围就把申请转交给部门经理这个下一个处理者。
- 请求(Request):这是需要在职责链中传递并被处理的对象,它包含了与请求相关的各种信息,例如请假申请中的请假天数、请假事由等内容。
-
优点
- 降低耦合度:请求的发送者不需要知道具体是哪个对象来处理请求,它只需要将请求发送到职责链的起始端即可,而各个具体处理者之间也只是通过链的方式依次传递请求,相互之间的依赖关系比较松散,便于系统的维护和扩展。
- 增强灵活性:可以动态地增加、删除或者重新排列职责链上的处理者,比如在请假审批系统中,如果公司组织结构调整,增加了新的管理层级或者调整了审批权限,只需要相应地修改或添加具体处理者类以及调整它们在链上的顺序就可以适应变化,而不需要大规模改动整个系统的其他部分。
- 便于分工协作:不同的具体处理者可以专注于处理自己职责范围内的请求,符合单一职责原则,有利于代码的编写、测试以及后续的维护工作。
-
缺点
- 可能导致性能问题:如果职责链比较长,而且每个请求都需要遍历较长的链才能找到合适的处理者,可能会消耗较多的时间和资源,特别是在对性能要求较高的场景下,这一点需要注意并合理优化。
- 调试难度增加:由于请求在多个对象之间传递,当出现问题时,确定是哪个环节的处理者出现故障或者错误的处理逻辑相对复杂一些,不利于快速定位和解决问题。
-
应用场景
- 审批流程:如前面提到的员工请假审批、费用报销审批等各种涉及多层级审批的场景,不同层级的审批人员构成职责链,根据审批权限来处理请求。
- 事件处理系统:在图形用户界面开发中,比如鼠标点击事件、键盘按键事件等,不同的控件或者组件可以按照一定的顺序构成职责链,根据各自的功能和逻辑来判断是否处理这些事件,比如先由按钮控件判断是否点击在自己范围内,如果不是再由父容器等继续判断处理。
- 客户服务系统:客户提出的问题按照问题的类型、难度等可以在不同的客服人员或者部门之间传递,例如一线客服先尝试解决简单问题,解决不了就转交给专业技术部门等,形成一条处理客户问题的职责链。
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
方法来设置下一个处理者。TeamLeader
、DepartmentManager
和GeneralManager
分别是具体的处理者类,它们继承自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 职责链模式的详细介绍 定义与概念 职责链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它旨在将请求的发送者和多个接收者解耦,让多个对象都有机会处理请求&a…...

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

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

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

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

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

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

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

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

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

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

8K+Red+Raw+ProRes422分享5个影视级视频素材网站
Hello,大家好,我是后期圈! 在视频创作中,电影级的视频素材能够为作品增添专业质感,让画面更具冲击力。无论是广告、电影短片,还是品牌宣传,高质量的视频素材都是不可或缺的资源。然而ÿ…...

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…...

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

Retrofit源码分析:动态代理获取Api接口实例,解析注解生成request,线程切换
目录 一,Retrofit的基本使用 1.定义api接口 2.创建Retrofit实例 3.获取api接口实例发起请求 二,静态代理和动态代理 1,静态代理 2,动态代理 三,动态代理获取Api接口实例 四,解析接口方法注解&…...

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

【中标麒麟服务器操作系统实例分享】java应用DNS解析异常分析及处理
了解更多银河麒麟操作系统全新产品,请点击访问 麒麟软件产品专区:https://product.kylinos.cn 开发者专区:https://developer.kylinos.cn 文档中心:https://document.kylinos.cn 情况描述 中标麒麟服务器操作系统V7运行在 ARM…...

网安瞭望台第17期:Rockstar 2FA 故障催生 FlowerStorm 钓鱼即服务扩张现象剖析
国内外要闻 Rockstar 2FA 故障催生 FlowerStorm 钓鱼即服务扩张现象剖析 在网络安全的复杂战场中,近期出现了一个值得关注的动态:名为 Rockstar 2FA 的钓鱼即服务(PhaaS)工具包遭遇变故,意外推动了另一个新生服务 Flo…...

玩转OCR | 探索腾讯云智能结构化识别新境界
📝个人主页🌹:Eternity._ 🌹🌹期待您的关注 🌹🌹 ❀ 玩转OCR 腾讯云智能结构化识别产品介绍服务应用产品特征行业案例总结 腾讯云智能结构化识别 腾讯云智能结构化OCR产品分为基础版与高级版&am…...

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

外连接转AntiJoin的应用场景与限制条件 | OceanBase SQL 查询改写系列
在《SQL 改写系列:外连接转内连接的常见场景与错误》一文中,我们了解到谓词条件可以过滤掉连接结果中的 null 情形的,将外连接转化为内连接的做法是可行的,正如图1中路径(a)所示。此时,敏锐的你或许会进一步思考&#…...

华为实训课笔记 2024 1223-1224
华为实训 12/2312/24 12/23 [Huawei]stp enable --开启STP display stp brief --查询STP MSTID Port Role STP State Protection 实例ID 端口 端口角色 端口状态 是否开启保护[Huawei]display stp vlan xxxx --查询制定vlan的生成树计算结…...

MySQL超详细安装配置教程(亲测有效)
目录 1.下载mysql 2.环境配置 3.安装mysql 4.navicat工具下载与连接 5总结 1.下载mysql mysql下载--MySQL :: 下载 MySQL 社区服务器 下载的时候这里直接逃过就行 我这里的版本是最新的mysql8.0.37 下载完成之后,将压缩包进行解压 这里我建议大…...

MySQL 8.0:explain analyze 分析 SQL 执行过程
介绍 MySQL 8.0.16 引入一个实验特性:explain formattree ,树状的输出执行过程,以及预估成本和预估返 回行数。在 MySQL 8.0.18 又引入了 EXPLAIN ANALYZE,在 formattree 基础上,使用时,会执行 SQL &#…...

信管通低代码信息管理系统应用平台
目前,国家统一要求事业单位的电脑都要进行国产化替代,替代后使用的操作系统都是基于linux的,所有以前在WINDOWS下运行的系统都不能使用了,再者,各单位的软件都很零散,没有统一起来。需要把日常办公相关的软…...

git推送本地仓库到远程(Gitee)
目录 一、注册创建库 二、创建仓库 三、推送本地仓库到远程 1.修改本地仓库用户名和邮箱 2.本地库关联远程仓库 3.拉取远程仓库的文件 4.推送本地库的文件 5.查看远程仓库 四、远程分支查看 1.查看远程分支 2.修改test.txt文件 一、注册创建库 Gitee官网࿱…...

【C++语言】多态
一、多态的概念 多态的概念:通俗来说,就是多种形态,具体点就是去完成某种行为,当不同的对象去完成时会产生出不同的状态。 我们可以举一个例子: 比如买票这种行为,当普通人买票时,是全价买票&am…...

ThinkPHP 吸收了Java Spring框架一些特性
ThinkPHP 吸收了Java Spring框架一些特性,下面介绍如下: 1、controller 控制器层 存放控制器层的文件,用于处理请求和响应 2、model 实体类 存放实体类的文件,用于定义数据模型 3、dao DAO层 存放DAO(数据访问…...

自动控制系统综合与LabVIEW实现
自动控制系统综合是为了优化系统性能,确保其可靠性、稳定性和灵活性。常用方法包括动态性能优化、稳态误差分析、鲁棒性设计等。结合LabVIEW,可以通过图形化编程、高效数据采集与处理来实现系统综合。本文将阐述具体方法,并结合硬件选型提供实…...

记录一个SVR学习
1、为什么使用jupter来做数据预测?而不是传统pycharm编辑器 1、Jupyter Notebook 通过anaconda统一管理环境,可以运行python、R、Sql等数据分析常用语言。 2、做到交互式运行,可以逐步运行代码块,实时查看结果,便于调…...