实战设计模式之责任链模式

概述

与上一篇介绍的命令模式一样,责任链模式也是一种行为设计模式,它允许我们将请求沿着处理者链进行传递。接收者和发送者都没有对方的引用,且责任链中的节点可以动态地添加或移除。这样,就避免了请求发送者与多个接收者的硬编码依赖,使系统更加灵活。

在下面三种应用场景中,我们可以毫不犹豫地使用责任链模式。

1、有多个对象可以处理一个请求,但事先并不确定哪个对象会真正处理该请求,我们可以根据运行时信息来决定。

2、想要在不明确指定接收者的情况下,向多个对象中的一个提交请求,即发送者不需要知道是谁最终处理了请求。

3、可以在不影响其他对象的情况下,动态地指定一组对象来处理请求。这意味着,我们可以随时调整链条上的处理者。

公司的审批流程是现实生活中运用责任链模式的一个典型例子:当员工提交一份报销单时,这份报销单可能会先经过部门经理的初步审核,然后是财务部门的进一步检查,最后可能是高层管理人员的最终批准。每个级别的审批人员都有权决定是否批准该报销单,或者将其转发给更高级别的审批人。

基本原理

责任链模式的核心思想在于:将请求的发送者与接收者进行解耦,通过建立一条链式结构,使得请求可以在链上的节点之间传递,直到有节点能够处理该请求为止。如果所有节点都无法处理,则请求可能最终未被处理或返回默认结果。责任链模式主要由以下三个核心组件构成。

1、抽象处理器。定义了一个接口,所有具体处理器都必须实现这个接口。通常情况下,抽象处理器会包含下面两个方法。

(1)SetNext:用于设置责任链中的下一个处理器。

(2)Handle:用于处理请求,如果当前处理器不能处理,则调用链中下一个处理器的Handle方法继续处理。

2、具体处理器。实现了抽象处理器的接口,提供了具体的业务逻辑来处理请求。每个具体处理器都决定自己是否能处理传入的请求,如果不能处理,则将请求转发给链中的下一个处理器。

3、客户端。创建并组装处理器链,然后向链的起点提交请求。客户端不需要知道链的具体结构,只需要知道如何启动处理流程即可。

基于上面的核心组件,责任链模式的实现主要有以下四个步骤。

1、定义抽象处理器。创建一个基类或接口,定义了处理请求的方法,以及设置下一个处理器的方法。

2、创建具体处理器。为每种类型的请求创建具体的处理器类,继承自抽象处理器,并实现处理逻辑。在Handle方法中,检查是否能处理请求。若不能,则调用链中的下一个处理器。

3、构建责任链。在客户端中,实例化各个具体处理器,并使用SetNext方法将它们链接起来,形成责任链。

4、发起请求。客户端只需向责任链的起点提交请求,而无需关心链的具体结构或长度。

实战解析

在下面的实战代码中,我们使用责任链模式实现了公司的审批流程。

首先,我们定义了抽象处理器类CHandler。CHandler定义了处理请求的基本框架,包含一个指向下一个处理器的指针m_pNext,以及设置下一个处理器的方法SetNext。同时,它还提供了一个虚函数Handle,用于处理请求或将其传递给下一个处理器。

然后,我们定义了三个具体处理器类。CDepartmentManager表示部门经理,可以批准金额小于等于1000美元的请求。CFinanceManager表示财务经理,可以批准金额小于等于5000美元的请求。CCeo表示CEO,可以批准任何金额的请求,但通常只处理超过5000美元的请求。

最后,在main函数中,我们创建了三个具体的处理器实例:部门经理、财务经理和CEO,并使用SetNext方法将这些处理器链接成一条责任链。我们向责任链发送了多个请求,每个请求都从链的起点(即部门经理)开始处理,直到找到能够处理该请求的处理器,或到达链的末端。

C++ 复制代码
#include <iostream>
#include <string>

using namespace std;

// 抽象处理器类
class CHandler
{
public:
    CHandler() : m_pNext(NULL) {}

    void SetNext(CHandler* pHandler)
    {
        m_pNext = pHandler;
    }

    virtual void Handle(const string& strReq)
    {
        if (m_pNext != NULL)
        {
            m_pNext->Handle(strReq);
        }
    }

protected:
    CHandler* m_pNext;
};

// 部门经理处理类
class CDepartmentManager : public CHandler
{
public:
    void Handle(const string& strReq) override
    {
        cout << "Department Manager is reviewing the request" << endl;
        // 金额小于等于1000,由部门经理审批
        int nAmount = atoi(strReq.c_str());
        if (nAmount <= 1000)
        {
            cout << "Department Manager approved the request for $" << nAmount << endl;
        }
        else
        {
            cout << "Amount exceeds Department Manager's authority, passing to next level" << endl;
            // 调用基类方法,传递给下一个处理器
            CHandler::Handle(strReq);
        }
    }
};

// 财务经理处理类
class CFinanceManager : public CHandler
{
public:
    void Handle(const string& strReq) override
    {
        cout << "Finance Manager is reviewing the request" << endl;
        // 金额小于等于5000,由财务经理审批
        int nAmount = atoi(strReq.c_str());
        if (nAmount <= 5000)
        {
            cout << "Finance Manager approved the request for $" << nAmount << endl;
        }
        else
        {
            cout << "Amount exceeds Finance Manager's authority, passing to next level" << endl;
            // 调用基类方法,传递给下一个处理器
            CHandler::Handle(strReq);
        }
    }
};

// 高层管理人员处理类
class CCeo : public CHandler
{
public:
    void Handle(const string& strReq) override
    {
        cout << "CEO is reviewing the request" << endl;
        int nAmount = atoi(strReq.c_str());
        // 金额大于5000,由CEO审批
        if (nAmount > 5000)
        {
            cout << "CEO approved the request for $" << nAmount << endl;
        }
        else
        {
            cout << "Request should have been handled by lower levels" << endl;
        }
    }
};

int main()
{
    // 创建处理器对象
    CDepartmentManager deptManager;
    CFinanceManager financeManager;
    CCeo ceo;

    // 组装责任链
    deptManager.SetNext(&financeManager);
    financeManager.SetNext(&ceo);

    // 发送请求
    string requests[] = {"888", "3600", "9999"};
    for (const auto& strReq : requests)
    {
        cout << "Processing request for $" << strReq << ":" << endl;
        // 从责任链的起点开始处理
        deptManager.Handle(strReq);
        cout << endl;
    }

    return 0;
}

总结

责任链模式有效解耦了发送者和接收者,发送请求的对象不需要知道哪个对象会处理请求。这减少了发送者与接收者之间的依赖,增强了系统的灵活性。责任链模式允许多个对象尝试处理一个请求,这一点特别适用于那些没有明确指定哪个对象应该处理特定类型的请求的情况,每个处理器都可以决定是否处理请求,或者将其传递下去。

但如果责任链过长,可能会导致请求遍历整个链条才能找到合适的处理器,从而增加处理时间。在某些情况下,确保处理器按照正确的顺序处理请求可能是必要的。然而,责任链模式本身并不保证这一点,必须通过其他机制来实现。

相关推荐
chenyuhao20248 分钟前
MySQL索引特性
开发语言·数据库·c++·后端·mysql
白衣鸽子18 分钟前
【基础数据篇】数据格式化妆师:Formatter模式
后端·设计模式
刘一说34 分钟前
Nacos 与 Spring Cloud Alibaba 集成详解:依赖、配置、实战与避坑指南
spring boot·spring cloud·微服务·架构
小龙报36 分钟前
【算法通关指南:数据结构和算法篇 】队列相关算法题:3.海港
数据结构·c++·算法·贪心算法·创业创新·学习方法·visual studio
辞旧 lekkk1 小时前
【c++】封装红黑树实现mymap和myset
c++·学习·算法·萌新
星轨初途1 小时前
C++的输入输出(上)(算法竞赛类)
开发语言·c++·经验分享·笔记·算法
极地星光1 小时前
Qt/C++ 单例模式深度解析:饿汉式与懒汉式实战指南
c++·qt·单例模式
ZHE|张恒2 小时前
设计模式(十八)命令模式 —— 将操作封装成对象,实现撤销、队列等扩展
设计模式·命令模式
yuuki2332332 小时前
【C++】类和对象(上)
c++·后端·算法
再睡一夏就好2 小时前
string.h头文件中strcpy、memset等常见函数的使用介绍与模拟实现
c语言·c++·笔记·string·内存函数·strcpy