C++ 设计模式之责任链模式

news2024/9/23 15:27:56

【声明】本题目来源于卡码网(卡码网KamaCoder)

【提示:如果不想看文字介绍,可以直接跳转到C++编码部分


设计模式大纲】


【简介】

        --什么是责任链模式(第21种设计模式)

        责任链模式是⼀种行为型设计模式,它允许你构建⼀个对象链,让请求从链的⼀端进⼊,然后沿着链上的对象依次处理,直到链上的某个对象能够处理该请求为止。

        职责链上的处理者就是⼀个对象,可以对请求进⾏处理或者将请求转发给下⼀个节点,这个场景在⽣活中很常⻅,就是⼀个逐层向上递交的过程,最终的请求要么被处理者所处理,要么处理不了,这也因此可能导致请求⽆法被处理。


 【组成结构】

        责任链模式包括以下几个基本结构:

  • 1. 处理者Handler :定义⼀个处理请求的接⼝,包含⼀个处理请求的抽象⽅法和⼀个指向下⼀个处理者的链接。
  • 2. 具体处理者ConcreteHandler : 实现处理请求的⽅法,并判断能否处理请求,如果能够处理请求则进⾏处理,否则将请求传递给下⼀个处理者。
  • 3. 客户端:创建并组装处理者对象链,并将请求发送到链上的第⼀个处理者


 【简易实现 - Java】

        以Java代码作以简要说明

1. 处理者

        定义处理请求的接口

interface Handler {
    // 处理请求的⽅法
    void handleRequest(double amount);
    // 设置下⼀个处理者的⽅法
    void setNextHandler(Handler nextHandler);
}

2. 具体处理者

        实现处理请求

class ConcreteHandler implements Handler {
    private Handler nextHandler;

    @Override
    public void handleRequest(Request request) {
        // 根据具体情况处理请求,如果⽆法处理则交给下⼀个处理者
        if (canHandle(request)) {
            // 处理请求的逻辑
        } else if (nextHandler != null) {
            // 交给下⼀个处理者处理
            nextHandler.handleRequest(request);
        } else {
            // ⽆法处理请求的逻辑
        }
    }

    @Override
    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    // 具体处理者⾃⼰的判断条件
    private boolean canHandle(Request request) {
        // 根据具体情况判断是否能够处理请求
        return /* 判断条件 */;
    }
}

3. 客户端

        创建并组装处理者对象链,将请求发送给链上第⼀个处理者

public class Main {
    public static void main(String[] args) {
        // 创建处理者实例
        Handler handler1 = new ConcreteHandler();
        Handler handler2 = new ConcreteHandler();
        // ...
        // 构建责任链
        handler1.setNextHandler(handler2);
        // ...
        // 发送请求
        Request request = new Request(/* 请求参数 */);
        handler1.handleRequest(request);
    }
}

【使用场景】

        责任链模式具有下⾯⼏个优点:

  • 降低耦合度:将请求的发送者和接收者解耦,每个具体处理者都只负责处理与⾃⼰相关的请求,客户端不需要知道具体是哪个处理者处理请求。
  • 增强灵活性:可以动态地添加或删除处理者,改变处理者之间的顺序以满⾜不同需求。

        但是由于⼀个请求可能会经过多个处理者,这可能会导致⼀些性能问题,并且如果整个链上也没有合适的处理者来处理请求,就会导致请求⽆法被处理。
        责任链模式是设计模式中简单且常⻅的设计模式,在⽇常中也会经常使⽤到,⽐如Java开发中过滤器的链式处理,以及Spring框架中的拦截器,都组装成⼀个处理链对请求、响应进⾏处理。


【C++编码部分】

1. 题目描述

        小明所在的公司请假需要在OA系统上发布申请,整个请求流程包括多个处理者,每个处理者负责处理不同范围的请假天数,如果一个处理者不能处理请求,就会将请求传递给下一个处理者,请你实现责任链模式,可以根据请求天数找到对应的处理者。

        审批责任链由主管(Supervisor), 经理(Manager)和董事(Director)组成,他们分别能够处理3天、7天和10天的请假天数。如果超过10天,则进行否决。

2. 输入描述

        第一行是一个整数N(1 <= N <= 100), 表示请求申请的数量。接下来的N行,每行包括一个请求申请的信息,格式为"姓名 请假天数"。

3. 输出描述

        对于每个请假请求,输出一行,表示该请求是否被批准。如果被批准/否决,输出被哪一个职级的人批准/否决。

4. C++编程示例(可直接运行)

/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file DutyChainMode.hpp
* @brief 责任链模式
* @autor 写代码的小恐龙er
* @date 2024/01/25
*/

#include <iostream>
#include <string>

using namespace std;

// 前置声明

// 用户请求类
class LeaveRequest;

//  处理者 接口类
class LeaveHandler;
// 具体处理者1 -- 主管(Supervisor) 3
class Supervisor;
// 具体处理者2 -- 经理(Manager) 7 
class Manager;
// 具体处理者3 -- 董事(Director) 10
class Director;

// 具体定义

// 用户请求类
class LeaveRequest
{
//成员数据
private:
    string _name;
    int _daysLeave = 0;
// 成员函数
public:
    //构造函数
    LeaveRequest(string name, int days){
        this->_name = name;
        this->_daysLeave = days;
    }
    // 成员数据获取接口
    string GetName(){
        return this->_name;
    }
    int GetDaysLeave(){
        return this->_daysLeave;
    }
};

//  处理者 接口类
class LeaveHandler
{
// 接口
public:
    virtual void HandleRequest(LeaveRequest *request) = 0;
};

// 具体处理者1 -- 主管(Supervisor) 3
class Supervisor : public LeaveHandler
{
//成员数据
private:
    const int _maxDays = 3;
    // 下一个处理者
    LeaveHandler *_nextHandler;
// 接口函数重载
public:
    // 构造函数
    Supervisor(){}
    Supervisor(LeaveHandler *nextHandler){
        this->_nextHandler = nextHandler;
    }
    void HandleRequest(LeaveRequest *request) override {
        if(request){
            if(request->GetDaysLeave() <= _maxDays){
                std::cout << request->GetName() << " Approved by Supervisor." << endl;
            }
            else if(_nextHandler){
                _nextHandler->HandleRequest(request);
            }
            else std::cout << request->GetName() << " Denied by Supervisor." << endl;
        }
    }
};

// 具体处理者2 -- 经理(Manager) 7 
class Manager : public LeaveHandler
{
//成员数据
private:
    const int _maxDays = 7;
    // 下一个处理者
    LeaveHandler *_nextHandler;
// 接口函数重载
public:
    // 构造函数
    Manager(){}
    Manager(LeaveHandler *nextHandler){
        this->_nextHandler = nextHandler;
    }
    void HandleRequest(LeaveRequest *request) override {
        if(request){
            if(request->GetDaysLeave() <= _maxDays){
                std::cout << request->GetName() << " Approved by Manager." << endl;
            }
            else if(_nextHandler){
                _nextHandler->HandleRequest(request);
            }
            else std::cout << request->GetName() << " Denied by Manager." << endl;
        }
    }
};

// 具体处理者3 -- 董事(Director) 10
class Director : public LeaveHandler
{
//成员数据
private:
    const int _maxDays = 10;
    // 下一个处理者
    const LeaveHandler *_nextHandler = nullptr;
// 接口函数重载
public:
    // 构造函数
    Director(){}
    // Director(LeaveHandler *nextHandler){
    //     this->_nextHandler = nextHandler;
    // }
    void HandleRequest(LeaveRequest *request) override {
        if(request){
            if(request->GetDaysLeave() <= _maxDays){
                std::cout << request->GetName() << " Approved by Director." << endl;
            }
            // else if(_nextHandler){
            //     _nextHandler->HandleRequest(request);
            // }
            else std::cout << request->GetName() << " Denied by Director." << endl;
        }
    }
};

int main()
{
    // 请求数量
    int requestNum = 0;
    std::cin >> requestNum;
    // 创建请求命令基类
    LeaveRequest *request = nullptr;
    // 创建处理者基类 -- 【创建处理流程时 也可单独创建一个类】
    LeaveHandler *director = new Director();
    LeaveHandler *manager = new Manager(director);
    LeaveHandler *supervisor = new Supervisor(manager);

    // 遍历
    for(int i = 0; i < requestNum; i++){
        // 请假者姓名 和 天数
        string name = "";
        int days = 0;
        // 输入
        std::cin >> name >> days;
        // 新建请求类
        request = new LeaveRequest(name, days);
        // 开始处理请求
        supervisor->HandleRequest(request);
    }
    
    //析构
    delete director;
    director = nullptr;

    delete manager;
    manager = nullptr;

    delete supervisor;
    supervisor = nullptr;
    
    if(request != nullptr){
        delete request;
        request = nullptr;
    }
    
    return 0;
}


......

To be continued.

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

bean的一生

你曾读spring源码 “不知所云”、“绞尽脑汁”、“不知所措”嘛&#x1f923;&#x1f923;&#x1f923; 那这篇文章可能会对你有所帮助&#xff0c;小编尝试用简单、易懂的例子来模拟spring经典代码&#x1f449;Spring Bean生命周期及扩展点&#xff0c; 让你能够****轻松…

Word中插入公式并引用

1、如何插入公式 在word中,键入快捷键 “alt” + “=”,即可快速插入一个公式,并立即编辑。 2、利用表格框住公式 新建一个 1 行 3 列的表格,总宽度为页面宽度,第一个单元格和最后一个单元格都保持在 2.25cm,中间尽可能长。我设置的这个数值比较合理。 记住,要把表格…

mask transformer相关论文阅读

前面讲了mask-transformer对医学图像分割任务是非常适用的。本文就是总结一些近期看过的mask-transformer方面的论文。 因为不知道mask transformer是什么就看了一些论文。后来得出结论&#xff0c;应该就是生成mask的transformer就是mask transformer。 相关论文&#xff1a; …

数据结构OJ题——二叉树前序、中序遍历非递归实现(Java版)

二叉树前序、中序遍历非递归实现 前序非递归遍历实现中序非递归遍历实现 前序非递归遍历实现 题目&#xff1a; 二叉树前序遍历非递归实现 总体思路&#xff1a;用非递归的方式模拟递归遍历。 以下图为例&#xff1a; 图示详解&#xff1a; 代码实现&#xff1a; /*** Defi…

【4.LCD显示】蓝桥杯嵌入式一周拿奖速成系列

系列文章目录 蓝桥杯嵌入式系列文章目录(更多此系列文章可见) 文章目录 系列文章目录LCD显示一、官方例程讲解二、main.c --> LcdProcess总结 LCD显示 因为官方给了我们LCD的例程,所以很easy,我们照着套就行 LcdProcess() 一、官方例程讲解 二、main.c --> LcdProcess…

143基于matlab的2D平面桁架有限元分析

基于matlab的2D平面桁架有限元分析&#xff0c;可以改变材料参数&#xff0c;输出平面结构外形&#xff0c;各桁架应力&#xff0c;位移及作用力。可查看节点力&#xff0c;程序已调通&#xff0c;可直接运行。 143 matlab 平面桁架 有限元分析 桁架应力 (xiaohongshu.com)

ubuntu下docker卸载和重新安装

卸载&#xff1a;步骤一&#xff1a;停止Docker服务 首先&#xff0c;我们需要停止正在运行的Docker服务。打开终端&#xff0c;执行以下命令&#xff1a; sudo systemctl stop docker 步骤二&#xff1a;删除Docker安装包 接下来&#xff0c;我们需要删除已经安装的Docker软件…

《WebKit 技术内幕》学习之六(3): CSS解释器和样式布局

3 WebKit布局 3.1 基础 当WebKit创建RenderObject对象之后&#xff0c;每个对象是不知道自己的位置、大小等信息的&#xff0c;WebKit根据框模型来计算它们的位置、大小等信息的过程称为布局计算&#xff08;或者称为排版&#xff09;。 图描述了这一过程中涉及的主要WebKit…

全球机器人产业:技术创新驱动下的市场与竞争新态势

原创 | 文 BFT机器人 近年来&#xff0c;随着颠覆性技术创新的不断涌现、市场新需求的迅速崛起以及外部冲击的深远影响&#xff0c;机器人产业正经历着前所未有的变革。在技术领域&#xff0c;机器人技术不断突破&#xff0c;智能化、自主化、协同化水平日益提升&#xff1b;在…

防火墙综合拓扑接口配置

目录 1、先给Server1、Server2&#xff0c;PC1、Client1、Client2、PC2配置IP、掩码、 网关。 2、LSW1 3、Cloud1 4、FW2 5、 Web界面配置防火墙 6、测试 1、先给Server1、Server2&#xff0c;PC1、Client1、Client2、PC2配置IP、掩码、 网关。 2、LSW1 [Huawei]int g …

明天见!跨越“白酒+文旅+文创”赛道,密鉴品牌将大幅焕新

执笔 | 洪大大 编辑 | 扬 灵 过去的2023年&#xff0c;外部环境的变化叠加产业周期的调整&#xff0c;使得行业呈现出更强的挤压态势&#xff0c;在此背景下&#xff0c;白酒品牌期望对各方资源进行高效整合与充分联动&#xff0c;以此来应对行业周期调整并适应产业升级步伐…

松散子序列(第十四届蓝桥杯省赛PythonB组)

给定一个仅含小写字母的字符串 s&#xff0c;假设 s 的一个子序列 t 的第 i 个字符对应了原字符串中的第 pi 个字符。 我们定义 s 的一个松散子序列为&#xff1a;对于 i>1 总是有 pi−pi−1≥2。 设一个子序列的价值为其包含的每个字符的价值之和&#xff08;a∼z 分别为…

【江科大】STM32:I2C通信外设(硬件)

在将2C通信外设之前&#xff0c;我们先捋一捋&#xff0c;串口的相关特点来和I2C进行一个对北比。 首先&#xff1a; 1,大部分单片机&#xff0c;设计的PCB板均带有串口通信的引脚&#xff08;也就是通信基本都借助硬件收发器来实现&#xff09; 2.对于串口的异步时序&#xff…

Hudi学习笔记(一)

大数据发展背景 Hudi用于管理分布式文件系统上大型分析数据集存储&#xff0c;支持Spark和Flink整合。它能够是DFS数据集在分钟级时延内支持变更&#xff0c;也支持下游系统对这个数据集的增量处理。 学习目标 什么是数据湖为什么使用数据湖Hudi基本功能如何编译Hudi源码Hud…

4 课程分类查询

4 课程分类查询 4.1 需求分析 下边根据内容管理模块的业务流程&#xff0c;下一步要实现新增课程&#xff0c;在新增课程界面&#xff0c;有三处信息需要选择&#xff0c;如下图&#xff1a; 课程等级、课程类型来源于数据字典表&#xff0c;此部分的信息前端已从系统管理服…

SpringMVC第四天(SSM整合)

SSM整合流程 1.创建工程 2.SSM整合 ①Spring SpringConfig package com.cacb.config;import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import;…

opencv#34 边缘检测(二)

Laplacian(拉普拉斯)算子 前面介绍的Sobel算子和Scharr算子存在的问题: 1.要分别计算两个方向&#xff08;x,y)的边缘&#xff0c;之后将两方向的边缘进行叠加。 2.边缘与方向相关性较大。当我们通过Sobel算子提取x方向检测时&#xff0c;它所能够检测到的边缘都是一个沿着y…

如何在转接的NVME 固态盘上安装WIN 系统并引导启动

问题&#xff1a; 家里的台式机一直挂着一块128G的SSD固态盘&#xff0c;由于家里自己建了NAS存储&#xff0c;所以基本数据都在NAS里&#xff0c;台式机就没有挂机械盘了&#xff0c;但是最近台式机空间被系统侵蚀&#xff0c;显然就不够用了&#xff0c;除了清理系统&#xf…

八数码(BFS + 队列 + 哈希表)

这题虽然比较难&#xff0c;但仍然遵循BFS的思路图片引自我的上一篇文章&#xff1a; 走迷宫&#xff08;BFS 队列&#xff09;-CSDN博客 难点 &#xff08;1&#xff09;如何将一个二维数组表示的状态记录下来&#xff0c;并且需要便于知道某个状态是否访问过 &#xff0…

Biotin-PEG4-TSA,生物素-PEG4-酪胺,用于标记蛋白质、核酸等生物分子

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;Biotin-PEG4-Tyramide&#xff0c;Biotin-PEG4-TSA&#xff0c;生物素-PEG4-酪胺&#xff0c;Biotin PEG4 Tyramide&#xff0c;Biotin PEG4 TSA 一、基本信息 产品简介&#xff1a;Biotin PEG4 Tyramide is compos…