C++设计模式——Chain of Responsibility职责链模式

news2024/9/20 0:01:44

一,职责链模式的定义

职责链模式,又被称为责任链模式,是一种行为型设计模式,它让多个对象依次处理收到的请求,直到处理完成为止。

职责链模式需要使用多个对象,其中的每个对象要么处理请求,要么将请求传递给下一个对象,该模式因此可以实现发送方与接收方的松散耦合。

在职责链模式中,一个对象可以被理解为处理器,每个处理器都包含对下一个处理器的引用,多个对象之间形成了一个链表的结构。

职责链模式在现实生活中的抽象实例:

审批流程:在流程中,当一个申请需要多级审批时,可以使用职责链模式。每一级审批者都是职责链的一部分。

银行账户验证:在银行系统中,需要对用户进行身份验证和授权操作,而验证操作涉及多个步骤。

异常处理:在程序开发中,每个异常处理器可以处理特定类型的异常,如果当前处理器无法解决,则传递给下一个处理器。

二,职责链模式的结构

职责链模式主要包含以下组件:

1.抽象处理器(Handler):

处理器的抽象类,声明处理请求的抽象接口,并持有对下一个处理器的引用。

2.具体处理器(ConcreteHandler):

继承自抽象处理器,包含了对处理请求接口的具体实现,负责处理特定类型的请求或将请求传递给下一个处理器。

3.客户端(Client):

负责创建处理器的实例,并将它们加入到职责链中。然后向第一个处理器发送请求,并等待职责链的返回结果。

组件之间的工作步骤如下:

1.客户端将请求传递给职责链中的第一个处理器。

2.第一个处理器尝试处理请求。如果处理成功,则结束处理过程并返回结果,如果无法处理,则将请求转发给下一个处理器。

3.下一个处理器重复步骤2,直到找到能够处理请求的处理器,或者职责链中没有更多的处理器。

4.客户端获得处理结果。

对应UML类图:

三,职责链模式代码样例

#include <iostream>
#include <string>
class Handler
{
protected:
       Handler* successor;
public:
       void setSuccessor(Handler* successor)
       {
              this->successor = successor;
       }
       virtual void handleRequest(const std::string& request) = 0;
};
class ConcreteHandler1 : public Handler
{
public:
       void handleRequest(const std::string& request) override
       {
              if (request == "Type1")
              {
                      std::cout << "Handling request of type Type1." << std::endl;
              }
              else if (successor != nullptr)
              {
                      successor->handleRequest(request);
              }
              else
              {
                      std::cout << "Unable to handle the request." << std::endl;
              }
       }
};
class ConcreteHandler2 : public Handler
{
public:
       void handleRequest(const std::string& request) override
       {
              if (request == "Type2")
              {
                      std::cout << "Handling request of type Type2." << std::endl;
              }
              else if (successor != nullptr)
              {
                      successor->handleRequest(request);
              }
              else
              {
                      std::cout << "Unable to handle the request." << std::endl;
              }
       }
};
class ConcreteHandler3 : public Handler
{
public:
       void handleRequest(const std::string& request) override
       {
              if (request == "Type3")
              {
                      std::cout << "Handling request of type Type3." << std::endl;
              }
              else if (successor != nullptr)
              {
                      successor->handleRequest(request);
              }
              else
              {
                      std::cout << "Unable to handle the request." << std::endl;
              }
       }
};
int main()
{
       Handler* handler1 = new ConcreteHandler1();
       Handler* handler2 = new ConcreteHandler2();
       Handler* handler3 = new ConcreteHandler3();
       handler1->setSuccessor(handler2);
       handler2->setSuccessor(handler3);
       handler1->handleRequest("Type2");
       handler1->handleRequest("Type3");
       handler1->handleRequest("Type4");
       delete handler1;
       delete handler2;
       delete handler3;
       return 0;
}

运行结果:

Handling request of type Type2.
Handling request of type Type3.
Unable to handle the request.

四,职责链模式的应用场景

命令处理器:比如在游戏或GUI应用中,用户可以发送各种操作命令,如“播放音乐”、“关闭窗口”,而具体执行过程由一系列处理器完成。

日志记录器:将不同严重等级的日志交给不同的处理器去打印。

Web服务开发:在Web服务中,对请求进行校验和过滤,如权限验证、数据校验等。

权限控制:在用户权限管理中,可以根据角色的不同职责分配不同的权限验证步骤。

消息路由:在网络通信中,将不同类型的消息分别发送给不同的处理程序。

五,职责链模式的优缺点

职责链模式的优点:

和命令模式类似,可以实现发送者和接收者的解耦。

灵活性强,可以修改职责链中的结构和顺序。

有扩展性,可以在最小改动的情况下添加新的处理器。

处理器可以在不同的职责链中重复使用。

职责链模式的缺点:

对请求的处理可能覆盖不全,导致bug的产生。

请求的处理过程十分冗长。

请求的传递涉及多个对象,性能开销大。

责任链需要被一直维护和管理。

六,代码实战

Demo1:日志记录器

#include <iostream>
#include <string>
#include <vector>
//Logger接口
class Logger {
public:
    virtual void log(const std::string& message) = 0;
};
//处理正常日志
class InfoLogger: public Logger{
public:
    void log(const std::string& message) override {
        std::cerr << "Info: " << message << std::endl;
    }
};
//处理调试日志
class DebugLogger: public Logger{
public:
    void log(const std::string& message) override {
        std::cout << "Debug: " << message << std::endl;
    }
};
//处理错误日志
class ErrorLogger: public Logger{
public:
    void log(const std::string& message) override {
        std::cerr << "Error: " << message << std::endl;
    }
};
class LoggingChain {
private:
    std::vector<std::shared_ptr<Logger>> loggers;
public:
    void addLogger(std::shared_ptr<Logger> logger) {
        loggers.push_back(logger);
    }
    void log(const std::string& message) {
        for (auto it = loggers.rbegin(); it != loggers.rend(); ++it) {
            (*it)->log(message);
        }
    }
};
int main() {
    LoggingChain chain;
    chain.addLogger(std::make_shared<InfoLogger>());
    chain.addLogger(std::make_shared<DebugLogger>());
    chain.addLogger(std::make_shared<ErrorLogger>());
    chain.log("This is a test message.");
    return 0;
}

运行结果:

Error: This is a test message.
Debug: This is a test message.
Info: This is a test message.

Demo2:模拟消息接收

#include <iostream>
#include <string>
#include <vector>
class Message {
public:
    virtual ~Message() {}
};
class TextMessage : public Message {
};
class ImageMessage : public Message {
};
class MessageHandler{
public:
    virtual void handle(Message* msg) = 0;
};
class TextProcessor: public MessageHandler{
public:
    void handle(Message* msg) override{
        if (dynamic_cast<TextMessage*>(msg)) {
            std::cout << "handling a text message." << std::endl;
            process(*static_cast<TextMessage*>(msg));
        }
        else {
            forward(msg);
        }
    }
private:
    void process(TextMessage& msg) {
    }
    void forward(Message* msg) {
    }
};
class ImageProcessor: public MessageHandler{
public:
    void handle(Message* msg) override {
        if (dynamic_cast<ImageMessage*>(msg)) {
            std::cout << "handling an image message." << std::endl;
            process(*static_cast<ImageMessage*>(msg));
        }
        else {
            forward(msg);
        }
    }
private:
    void process(ImageMessage& img){
    }
    void forward(Message* msg){
    }
};
class ChainOfResponsibility {
public:
    void setHandler(MessageHandler* handler){
        current_ = handler;
    }
    void handle(Message* msg) {
        current_->handle(msg);
    }
private:
    MessageHandler* current_ = nullptr;
};
int main() {
    ChainOfResponsibility chain;
    TextProcessor txtProc;
    ImageProcessor imgProc;
    chain.setHandler(&txtProc);
    chain.handle(new TextMessage());
    chain.setHandler(&imgProc);
    chain.handle(new ImageMessage());
    return 0;
}

运行结果:

handling a text message.
handling an image message.

七,参考阅读

https://www.geeksforgeeks.org/chain-responsibility-design-pattern/

https://www.tutorialspoint.com/design_pattern/chain_of_responsibility_pattern.htm

https://sourcemaking.com/design_patterns/chain_of_responsibility

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

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

相关文章

『功能项目』坐骑UI搭建及脚本控制显/隐【19】

本章项目成果展示 我们打开上一篇18怪物消亡掉落宝箱的项目&#xff0c; 本章要做的事情是搭建一个坐骑UI界面&#xff0c;并通过键盘B键/右侧坐骑按钮控制坐骑UI界面的显示与隐藏 在背包Bag上创建一个父物体&#xff0c; 命名为Middle 修改Bag的尺寸 将下面资源图片放进Art文…

开源|FormCreate低代码表单在弹窗中渲染表单时表单的值没有正常清空解决方法

如何在弹窗中通过低代码表单 FormCreate 渲染表单&#xff0c;包括表单的配置、表单验证、以及表单提交的处理。 源码地址: Github | Gitee <template><div><!-- 触发弹窗的按钮 --><el-button type"primary" click"showDialog true&quo…

国家商用密码算法——SM1、SM2、SM3

1、SM1 SM1 是中国国家密码管理局&#xff08;SCA&#xff09;发布的国密算法之一&#xff0c;属于对称加密算法&#xff0c;其分组长度、秘钥长度都是128bit。 【注】对称加密算法是一种使用相同密钥进行数据加密和解密的加密方式。在这种算法中&#xff0c;发送方和接收方共…

将本地的 IntelliJ IDEA 项目导入到 GitLab 上——超详细图文教程

要将本地的 IntelliJ IDEA 项目导入到 GitLab 上&#xff0c;可以按照以下详细步骤进行操作&#xff1a; 1. 在 GitLab 上创建一个新的仓库 打开 GitLab 或公司内部的 GitLab 服务器。 登录你的 GitLab 账号。 点击右上角的 号按钮&#xff0c;然后选择 “New Project”。 …

清华MEM作业-利用管理运筹学的分析工具slover求解最优解的实现 及 通过使用文件或者套节字来识别进程的fuser命令

一、清华MEM作业-利用管理运筹学的分析工具slover求解最优解的实现 最近又接触了一些线性求解的问题&#xff0c;以前主要都是在高中数学里接触到&#xff0c;都是使用笔算&#xff0c;最后通过一些函数式得出最小或者最大值&#xff0c;最近的研究生学业上接触到了一个Excel s…

C++入门基础知识50——【关于C++数字】之C++ 数学运算

成长路上不孤单&#x1f60a;【14后&#xff0c;C爱好者&#xff0c;持续分享所学&#xff0c;如有需要欢迎收藏转发&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#xff01;&#xff01;&#xff01;&#xff01;&#xff…

C++string类相关OJ练习(2)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 Cstring类相关OJ练习(2) 收录于专栏【C语法基础】 本专栏旨在分享学习C的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 目录 1.反转字符串 …

录屏软件电脑,精选5款录屏神器推荐

嘿&#xff0c;朋友们&#xff01;想象一下&#xff0c;你正在与好友分享你最新的游戏成就&#xff0c;或是与同事展示你的最新项目进展&#xff0c;但却发现文字描述无法完美呈现你的精彩瞬间。别担心&#xff0c;在这个数字化的时代&#xff0c;我们有着无数种方式记录和分享…

大型集团行业ITSM案例分析报告

一、项目背景 随着信息化建设的不断推进&#xff0c;大型集团的信息系统规模迅速扩大&#xff0c;业务系统对IT的依赖程度逐渐加深&#xff0c;IT网络应用系统的复杂度也随之增加。然而&#xff0c;相对滞后的运维服务体系却未能同步跟进&#xff0c;运维要求不断提高的同时&a…

SparkRA带你读论文 | 如何训练数据高效的 LLMs

简介 How to Train Data-Efficient LLMs 论文作者&#xff1a; Noveen Sachdeva, Benjamin Coleman, Wang-Cheng Kang, Jianmo Ni, Lichan Hong Ed H. Chi, James Caverlee, Julian McAuley, Derek Zhiyuan Cheng 论文链接&#xff1a; https://arxiv.org/pdf/2402.09668.pd…

Java CRM客户关系管理系统源码:基于Spring Cloud Alibaba与Spring Boot,专为成长型企业设计

项目名称&#xff1a;CRM客户关系管理系统 功能模块及描述&#xff1a; 一、待办事项 今日需联系客户&#xff1a;显示当日需跟进的客户列表&#xff0c;支持查询和筛选。分配给我的线索&#xff1a;管理分配给用户的线索&#xff0c;包括线索列表和查询功能。分配给我的客户…

Hive数据库与表操作全指南

目录 Hive数据库操作详解 创建数据库 1&#xff09;语法 2&#xff09;案例 查询数据库 1&#xff09;展示所有数据库 &#xff08;1&#xff09;语法 &#xff08;2&#xff09;案例 2&#xff09;查看数据库信息 &#xff08;1&#xff09;语法 &#xff08;2&#…

【免费分享】嵌入式Linux开发板【入门+项目,应用+底层】资料包一网打尽,附教程/视频/源码...

想要深入学习嵌入式Linux开发吗&#xff1f;现在机会来了&#xff01;我们为初学者们准备了一份全面的资料包&#xff0c;包括原理图、教程、课件、视频、项目、源码等&#xff0c;所有资料全部免费领取&#xff0c;课程视频可试看&#xff08;购买后看完整版&#xff09;&…

U盘提示需要格式化才能使用怎么办?教你轻松应对

U盘作为一种便捷的数据存储设备&#xff0c;广泛应用于日常工作和生活中。然而&#xff0c;有时我们会遇到U盘插入电脑后提示需要格式化才能使用的情况&#xff0c;这让人倍感焦虑&#xff0c;因为格式化往往意味着数据丢失。不过&#xff0c;在采取极端措施之前&#xff0c;我…

如何验证mos管好坏

用万用表的二极管档位测试&#xff0c;只有D&#xff08;&#xff09;S&#xff08;-&#xff09;之间电压低于0.7v&#xff0c;其他任意两脚之间电压都是大于1.5V。这是正常的。

不限专业和工作经验,这个含金量巨高的IT证书,90%的大学生都不知道!

软考现在正在报名阶段&#xff0c;大学生们千万不要错过&#xff01;这个IT证书的含金量巨高&#xff0c;对你的大学生涯乃至毕业后的职业规划都有帮助&#xff01; 下面就来为大家详细讲解一番&#xff0c;速速码住&#xff01; 1、软考报名条件 软考报名没有学历、资历、年龄…

【Python常用库_1】网络安全清洁专家——Bleach

前言&#xff1a; &#x1f60a;&#x1f60a;&#x1f60a;欢迎来到本博客&#x1f60a;&#x1f60a;&#x1f60a; &#x1f31f;&#x1f31f;&#x1f31f; 本专栏主要分享常用的一些Python库&#xff0c;让工作学习事半功倍&#xff0c;适用于平时学习、工作快速查询等…

CPP多态

目录 前言 多态的概念 多态的定义及实现 多态的构成条件 虚函数 虚函数的重写 虚函数重写的两个例外 C11 override 和 final 重载、覆盖(重写)、隐藏(重定义)的对比 抽象类 接口继承和实现继承 多态的原理 虚函数表 多态的原理 动态绑定与静态绑定 单继承和多继…

Aspose.PDF功能演示:在 C# 中将 JPG 图像合并为 PDF

Aspose.PDF 是一款高级PDF处理API&#xff0c;可以在跨平台应用程序中轻松生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现&#xff0c;保护和打印文档。无需使用Adobe Acrobat。此外&#xff0c;API提供压缩选项&#xff0c;表创建和处理&#xff0c;图形和图像功能&am…

网安新声 | 智能家居时代,用户隐私谁来守护

网安加社区【网安新声】栏目&#xff0c;汇聚网络安全领域的权威专家与资深学者&#xff0c;紧跟当下热点安全事件、剖析前沿技术动态及政策导向&#xff0c;以专业视野和前瞻洞察&#xff0c;引领行业共同探讨并应对新挑战的策略与可行路径。 近日&#xff0c;某知名品牌旗下的…