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

embedded/2024/12/26 11:34:48/

文章目录

      • 职责链模式的详细介绍
      • 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;
}

http://www.ppmy.cn/embedded/148881.html

相关文章

Leetcode 695 Max Area of Island

题意 给定一个二维矩阵&#xff0c;矩阵中包含0和1&#xff0c;所有相连的1被视为一个岛屿&#xff0c;求这些所有岛屿的最大区域是多少 题目链接 https://leetcode.com/problems/max-area-of-island/description/ 题解 遍历二维矩阵&#xff0c;当遇到没有被访问过的1时&…

【Linux进程】进程信号

目录 1. 信号 2. 信号的产生 2.1 终端按键 自定义信号处理 2.2 系统调用 kill raise abort 2.3 硬件异常 2.4 软件条件产生 思考 总结 1. 信号 在Linux中存在着一种通信的方式&#xff0c;与管道和System V IPC不同&#xff0c;更准确的说是一种通知机制&#xff0c;…

如何查看flink错误信息

flink出错时&#xff0c;可以通过以下步骤查看flink错误信息&#xff1a; 1.打开flink webui界面 2.进入overview或running jobs页面 3.点击出错的job name&#xff0c;出错的jobname一般后面的status会变红 4.在job 详情页面&#xff0c;点击exception&#xff0c;即可查看错…

eth_type_trans 函数

eth_type_trans 是 Linux 内核网络子系统中的一个函数,它主要用于确定接收到的以太网数据包(Ethernet frame)的协议类型,并设置相应的 sk_buff 结构体的协议字段。以下是关于 eth_type_trans 的详细解释: 功能 eth_type_trans 函数的主要功能是根据以太网数据包的目的 M…

Flink中并行度和slot的关系——任务和任务槽

一、任务槽&#xff08;task slots) Flink的每一个TaskManager是一个JVM进程&#xff0c;在其上可以运行多个线程&#xff08;任务task&#xff09;&#xff0c;那么每个线程可以拥有多少进程资源呢&#xff1f;任务槽就是这样一个概念&#xff0c;对taskManager上每个任务运行…

w118共享汽车管理系统

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;原创团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文…

LightGBM分类算法在医疗数据挖掘中的深度探索与应用创新(上)

一、引言 1.1 医疗数据挖掘的重要性与挑战 在当今数字化医疗时代,医疗数据呈爆炸式增长,这些数据蕴含着丰富的信息,对医疗决策具有极为重要的意义。通过对医疗数据的深入挖掘,可以发现潜在的疾病模式、治疗效果关联以及患者的健康风险因素,从而为精准医疗、个性化治疗方…

Elasticsearch 国产化替代方案之一 Easysearch 的介绍与部署指南

一、前言 在国内数字化转型浪潮和 信创 大背景下&#xff0c;“替代进口”成为许多企业级应用所需要面对的重要课题&#xff0c;搜索领域也不例外。 Elasticsearch&#xff08;简称 ES&#xff09;作为一款业界领先的全文搜索和分析引擎&#xff0c;虽然功能强大&#xff0c;但…