设计模式之责任链模式

面向对象设计原则

接口隔离原则面向对象设计之接口隔离原则-CSDN博客
设计模式

工厂模式设计模式之工厂模式-CSDN博客

迭代器模式设计模式之迭代器模式-CSDN博客

适配器模式设计模式之适配器模式-CSDN博客

过滤器模式设计模式之过滤器模式-CSDN博客

单例模式设计模式之单例模式-CSDN博客

观察者模式设计模式之观察者模式-CSDN博客

空对象模式设计模式之空对象模式-CSDN博客

桥接模式设计模式之桥接模式-CSDN博客

策略模式设计模式之策略模式-CSDN博客

责任链模式设计模式之责任链模式-CSDN博客

目录

1.概述

2.结构

3.实现

4.总结


1.概述

责任链模式(Chain of Responsibility Pattern)是一种行为性设计模式;它为请求创建了一个接收者对象的链,允许你将请求沿着处理者链进行发送。 收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。这种处理方法类似包与包之间的调用的思路,只是其可以不在主程序中累赘的去申明一堆if else变量使得程序更加臃肿。在我的博客中就是利用责任链模式来消除多层if-else-if。

C++之多层 if-else-if 结构优化(二)_c++ 怎么优化很多if 的代码呢-CSDN博客

2.结构

责任链模式的重点是在"链"上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果,其通用类图如下图所示:

角色定义:

抽象处理者(Handler): 定义一个处理请求的接口,通常包含一个处理请求的方法(如 handleRequest)和一个指向下一个处理者的引用(后继者),一般这类情况class内部都是纯虚函数。
**具体处理者(ConcreteHandler):**实现了抽象处理者接口,负责处理请求。如果能够处理该请求,则直接处理;否则,将请求传递给下一个处理者;这样可以通过设计整个逻辑链避免混乱。
**客户端(Client):**创建处理者对象,并将它们连接成一条责任链。通常,客户端只需要将请求发送给责任链的第一个处理者,无需关心请求的具体处理过程。

3.实现

以公司的请假为例,普通员工请假小于等于2天只需要自己的组长同意,请假大于2天小于等于5天需要部门经理同意,大于5天小于10天需要公司总经理同意才行,大于10天的请不了。根据上面的需求,我们可以先抽象Handler,再定义组长、部门经理、总经理,代码如下:

cpp 复制代码
#include <iostream>
using namespace std;

//抽象处理者
class Handler
{
public:
    explicit Handler() { m_pNextHandler = NULL; }
    virtual ~Handler() {}

    //设置下一个处理者
    void setNextHandler(Handler *successor) { m_pNextHandler = successor; }

    //处理请求
    virtual void HandleRequest(int days) = 0;
protected:
    Handler *m_pNextHandler;  // 后继者
};


//组长
class CGroupLeader : public Handler
{
public:
    //处理请求
    void HandleRequest(int days) override
    {
        if (days <= 2)
        {
            cout << "我是组长,有权批准" << days << "天假,同意了!" << endl; 
        }
        else
        {
            m_pNextHandler->HandleRequest(days);
        }
    }
};

//部门经理
class CDeptManager : public Handler
{
public:
    //处理请求
    void HandleRequest(int days)  override
    {
        if (days <= 5)
        {
            cout << "我是部门经理,有权批准" << days << "天的假,同意了!" << endl;
        }
        else
        {
            m_pNextHandler->HandleRequest(days);
        }
    }
};

//总经理
class  CGeneralManager : public Handler
{
public:
    //处理请求
    void HandleRequest(int days) override
    {
        if (days <= 10)
        {
            cout << "我是总经理,最多让你请10天假,同意了!" << endl;
        }
        else
        {
            cout << "你请的假时间太长了,不同意!" << endl;
        }
    }
};

测试用例:

cpp 复制代码
#include <memory>

int main()
{
    std::unique_ptr<Handler> pGroupLeader = new CGroupLeader;
    std::unique_ptr<Handler> pDeptLeader = new CDeptManager;
    std::unique_ptr<Handler> pGeneralManager = new CGeneralManager;

    //设置责任链
    pGroupLeader->setNextHandler(pDeptLeader.get());
    pDeptLeader->setNextHandler(pGeneralManager.get());

    pGroupLeader->HandleRequest(1);
    pGroupLeader->HandleRequest(2);
    pGroupLeader->HandleRequest(5);
    pGroupLeader->HandleRequest(8);
    pGroupLeader->HandleRequest(12);
    return 0;
}

输出:

cpp 复制代码
我是组长,有权批准1天假,同意了!
我是组长,有权批准2天假,同意了!
我是部门经理,有权批准5天的假,同意了!
我是总经理,最多让你请10天假,同意了!
你请的假时间太长了,不同意!

4.总结

优点:

解耦: 责任链模式将请求的发送者和接收者解耦,请求的发送者不需要知道接收者是谁,也不需要创建接收者的实例。同时,接收者也不需要知道请求的具体内容,只需要按照自已的业务逻辑进行相应的处理。这种解耦方式使得系统更加灵活,降低了耦合度,方便进行模块化开发和测试。
链式处理:责任链模式可以形成一个处理链,请求在这个链中传递,每个节点都会对请求进行处理,这种方式可以实现复杂的业务逻辑,提高系统的可扩展性和可维护性。
动态添加节点:在运行时,可以通过动态添加或册除节点来改变处理链,从而实现动态地扩展或修改处理逻辑。这种动态性使得系统更加灵活,能够适应不同的需求变化。

缺点:

错误传播:在责任链模式中,如果某个节点处理请求时出现了错误,这个错误会沿看处理链向上传播,可能会导致整个链路崩溃。为了解决这个问题,需要确保每个节点都进行了错误处理,能够在出现错误时进行适当的处理或回退操作。
无法终止链路:在某些情况下,如果请求不满足某个节点的条件,该节点就不需要对请求进行处理,但责任链模式无法直接终止链路。为了解决这人问题,可以在节点中添加判断逻辑,当请求不满足条件时直接返可或者进行其他处理。
性能问题:由于请求会在多个节点间传递,因此责任链模式的性能可能会受到影响。特别是在请求量较大或处理逻辑较复杂的情况下,这种影响会更加明显。为了解决这个问题,可以对节点进行优化,提高处理效率,同时也可以考虑使用缓存等方式来降低请求的重复处理。
节点之间的依赖关系:在责任链模式中节点之间存在依赖关系,如果每个节点的处理逻辑发生了变化,可能会影响到其它节点。这种依频关系可能会导致系统复杂度增加,增加了维护的难度。为了避免这种情况,可以尽量减少节点之间的依赖关系,使每个节点都尽可能独立地处理请求。同时也可以采用模块化设计等方式来降低系统复杂度。

相关推荐
可均可可29 分钟前
C++之OpenCV入门到提高004:Mat 对象的使用
c++·opencv·mat·imread·imwrite
白子寰1 小时前
【C++打怪之路Lv14】- “多态“篇
开发语言·c++
小芒果_011 小时前
P11229 [CSP-J 2024] 小木棍
c++·算法·信息学奥赛
gkdpjj1 小时前
C++优选算法十 哈希表
c++·算法·散列表
王俊山IT1 小时前
C++学习笔记----10、模块、头文件及各种主题(一)---- 模块(5)
开发语言·c++·笔记·学习
-Even-1 小时前
【第六章】分支语句和逻辑运算符
c++·c++ primer plus
我是谁??2 小时前
C/C++使用AddressSanitizer检测内存错误
c语言·c++
发霉的闲鱼2 小时前
MFC 重写了listControl类(类名为A),并把双击事件的处理函数定义在A中,主窗口如何接收表格是否被双击
c++·mfc
小c君tt2 小时前
MFC中Excel的导入以及使用步骤
c++·excel·mfc
xiaoxiao涛2 小时前
协程6 --- HOOK
c++·协程