重温设计模式--5、职责链模式
文章目录
- 职责链模式的详细介绍
- 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;
}
相关文章:

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

下午四点半
客户的员工竟然背着公司开发报表系统,是在密谋什么大事吗? 之前去线下给客户的员工培训,当时我就对这个小姑娘印象很深刻,因为她后面加了我们的技术人员,问了很多问题,不同于从来没有用过低代码平台的人&a…...
嵌入式单片机中Flash存储器控制与实现
第一:嵌入式单片机内部Flash概述 1.存储器的概念 存储器指的是若干个存储单元的集合,每个存储单元都可以存储若干个二进制数,为了方便的操作存储单元,就为每个存储单元都分配了地址,就可以通过寻址来访问存储单元。由于计算机的处理的数据量较大,并且运算速度都很快,就…...
loki failed to flush
loki 报错 levelerror ts2024-12-27T08:13:10.450140686Z callerflush.go:143 org_idfake msg"failed to flush" err"failed to flush chunks: store put chunk: open /data/loki/chunks/ZmFrZS85ODBmM2U3NzliODg2MjY1OjE5M2VhNDVkYTc4OjE5M2VhNDVlNDdkOjVmMjA…...
微信小程序打印生产环境日志
微信小程序打印生产环境日志 新建一个log.js文件,写入以下代码: let log wx.getRealtimeLogManager ? wx.getRealtimeLogManager() : nullmodule.exports {debug() {if (!log) returnlog.debug.apply(log, arguments)},info() {if (!log) returnlog.i…...

利用 deepin-IDE 的 AI 能力,我实现了文件加密扩展
经过多轮迭代,deepin 文件管理器(dde-file-manager)的扩展功能已经趋于稳定,看到越来越丰富的文管新功能,作为一名技术爱好者,也想自己动手写个插件扩展一下文管的功能。 我选择的开发工具是 deepin-IDE&a…...

JPA 基本查询(五)
JPA 查询Exists示例 JPA教程 - JPA 查询Exists示例 如果子查询返回任何行,则EXISTS条件返回true。 以下代码显示如何在JPQL中使用带有子查询的EXISTS运算符。 List l em.createQuery("SELECT e FROM Professor e WHERE EXISTS " "(SELECT p FROM …...

hiprint结合vue2项目实现静默打印详细使用步骤
代码地址是:vue-plugin-hiprint: hiprint for Vue2/Vue3 ⚡打印、打印设计、可视化设计器、报表设计、元素编辑、可视化打印编辑 本地安装包地址:electron-hiprint 发行版 - Gitee.com 1、先安装hipint安装包在本地 2、项目运行npm(socket.…...

项目报 OutOfMemoryError 、GC overhead limit exceeded 问题排查以及解决思路实战
项目报 OutOfMemoryError、GC overhead limit exceeded 问题排查以及解决思路实战 前言: 问题现象描述: 1,生产环境有个定时任务,没有初始化告警数据【告警数据量为1000多个】 2,其他定时任务执行正常 3,查…...

【计算机-显示屏灰阶测试】
硬计算机-显示屏灰阶测试 ■ 对比度■ 清晰度■ 灰度色阶(色带)■ 对比率■■ ■ 对比度 在一个性能良好的显示器上,您可观察到每种颜色的标尺都可分为从 1 至 32、大致上等宽但不同亮度的色带。即使是在刻度1处的色带也应该隐约可见。 一个…...
CSS系列(40)-- Container Queries详解
前端技术探索系列:CSS Container Queries详解 📦 致读者:探索组件响应式的艺术 👋 前端开发者们, 今天我们将深入探讨 CSS Container Queries,这个强大的组件级响应式特性。 基础概念 🚀 容…...

工作生活做事慢效率低原因及解决方案
时间和效率管理具体版(初阶)(一) 工作&生活做事慢效率低原因及解决方案 一、效率慢的原因(动物解析法(编者自创)) 打败你的可能是生活的小事 1.无头苍蝇无流程 做事之前没有想…...

各种数据库类型介绍
在软件开发和数据处理领域,数据库扮演着至关重要的角色。它们用于存储、检索和管理大量数据,是信息系统不可或缺的基础。以下是几种常用的数据库类型及其简要介绍: 1.关系型数据库(Relational Databases) 关系型数据库…...
了解智能运维
智能运维 (一)运维工作的转变 随着技术发展,运维工作从基础的搬机器、插网线、装系统等体力活儿,逐渐转变为更侧重服务器管理、代码管理、日志分析、监控告警、流量管理及故障排查等的脑力劳动。如今,运维人员拿到的…...
js实现仿windows文件名称排序
引言: 在JavaScript中,数组排序是一个常见的操作,但默认的Array.sort()方法只能进行简单的字符串比较。在处理复杂数据时,我们需要自定义排序函数来满足特定的需求。本文将通过一个具体的代码示例,解释如何实现一个仿w…...

基于Oauth2的SSO单点登录---前端
Vue-element-admin 是一个基于 Vue.js 和 Element UI 的后台管理系统框架,提供了丰富的组件和功能,可以帮助开发者快速搭建现代化的后台管理系统。 一、基本知识 (一)Vue-element-admin 的主要文件和目录 vue-element-admin/ |--…...
springboot 使用注解设置缓存时效
springboot 使用注解设置缓存时效 import org.apache.commons.lang3.StringUtils; import org.springframework.data.redis.cache.RedisCache; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCach…...

QGIS二次开发(地图符号库操作)
实习三 地图符号库操作 3.1 任务要求 基于QGIS,实现地图符号的设计/存储与显示;基于QGIS实现一个点、线、面shp矢量图层文件的显示。通过设置引用的符号,改变矢量图层的显示效果;可编辑地图的符号库汇中的点符号、线符号、面符号…...

线性代数行列式
目录 二阶与三阶行列式 二元线性方程组与二阶行列式 三阶行列式 全排列和对换 排列及其逆序数 对换 n阶行列式的定义 行列式的性质 二阶与三阶行列式 二元线性方程组与二阶行列式 若是采用消元法解x1、x2的话则得到以下式子 有二阶行列式的规律可得:分…...
Vision Transformer (ViT) 论文的第二句话
Vision Transformer (ViT) 论文的第二句话 flyfish 原句: “In vision, attention is either applied in conjunction with convolutional networks, or used to replace certain components of convolutional networks while keeping their overall structure in…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...

什么是库存周转?如何用进销存系统提高库存周转率?
你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...