• 16 C++设计模式之职责链(Chain of Responsibility)模式


    职责链(Chain of Responsibility)模式定义

    职责链模式(Chain of Responsibility),使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

    职责链(Chain of Responsibility)模式优缺点

    优点
    • 你可以控制请求处理的顺序。
    • 单一职责原则。你可对发起操作和执行操作的类进行解耦。
    • 开闭原则。你可以在不更改现有代码的情况下在程序中新增 处理者
    缺点
    • 部分请求可能未被处理

    职责链(Chain of Responsibility)模式构成与实现

    构成
    • 处理者(Handler)声明了所有具体处理者的通用接口。该接口通常仅包含单个方法用于请求处理,但有时其还会包含一个设置链上下个处理者的方法。
    • 基础处理者(Base Handler)是一个可选的类, 你可以将所有处理者共用的样本代码放置在其中。通常情况下,该类中定义了一个保存对于下个处理者引用的成员变量。客户端可通过将处理者传递给上个处理者的构造函数或设定方法来创建链。该类还可以实现默认的处理行为:确定下个处理者存在后再将请求传递给它。
    • 具体处理者(Concrete Handlers)包含处理请求的实际代码。每个处理者接收到请求后,都必须决定是否进行处理,以及是否沿着链传递请求。处理者通常是独立且不可变的,需要通过构造函数一次性地获得所有必要地数据。
    • 客户端(Client)可根据程序逻辑一次性或者动态地生成链。值得注意的是,请求可发送给链上的任意一个处理者,而非必须是第一个处理者。
    实例

    Handler.h:

    #ifndef HANDLER_H_
    #define HANDLER_H_
    
    // 抽象处理者, 在C++中是抽象基类
    class ApproverInterface {
     public:
        // 添加上级
        virtual void setSuperior(ApproverInterface* superior) = 0;
        // 处理票据申请, 参数是票据面额
        virtual void handleRequest(double amount) = 0;
    };
    
    #endif  // HANDLER_H_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    BaseHandler.h:

    #ifndef BASE_HANDLER_H_
    #define BASE_HANDLER_H_
    
    #include 
    #include "Handler.h"
    
    class BaseApprover : public ApproverInterface {
     public:
        BaseApprover(double mpa, std::string n) : max_processible_amount_(mpa), name_(n), superior_(nullptr) {}
        // 设置上级
        void setSuperior(ApproverInterface* superior) {
            superior_ = superior;
        }
        // 处理票据
        void handleRequest(double amount) {
            // 可处理时直接处理即可
            if (amount <= max_processible_amount_) {
                printf("%s处理了该票据, 票据面额:%f\n", name_.c_str(), amount);
                return;
            }
            // 无法处理时移交给上级
            if (superior_ != nullptr) {
                printf("%s无权处理, 转交上级...\n", name_.c_str());
                superior_->handleRequest(amount);
                return;
            }
            // 最上级依然无法处理时报错
            printf("无人有权限处理该票据, 票据金额:%lf\n", amount);
        }
    
     private:
        double max_processible_amount_;  // 可处理的最大面额
        std::string name_;
        ApproverInterface* superior_;
    };
    
    #endif  // BASE_HANDLER_H_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    ConcreteHandler.h:

    #ifndef CONCRETE_HANDLER_H_
    #define CONCRETE_HANDLER_H_
    
    #include 
    #include 
    #include "BaseHandler.h"
    
    // 具体处理者: 组长(仅处理面额<=10的票据)
    class GroupLeader : public BaseApprover {
     public:
        explicit GroupLeader(std::string name) : BaseApprover(10, name) {}
    };
    
    // 具体处理者: 经理(仅处理面额<=100的票据)
    class Manager : public BaseApprover {
     public:
        explicit Manager(std::string name) : BaseApprover(100, name) {}
    };
    
    
    // 具体处理者: 老板(仅处理面额<=1000的票据)
    class Boss : public BaseApprover {
     public:
        explicit Boss(std::string name) : BaseApprover(1000, name) {}
    };
    
    #endif  // CONCRETE_HANDLER_H_
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    main.cpp

    #include "ConcreteHandler.h"
    
    int main() {
        system("chcp 65001");
        // 请求处理者: 组长、经理和老板
        GroupLeader* group_leader = new GroupLeader("张组长");
        Manager* manager = new Manager("王经理");
        Boss* boss = new Boss("李老板");
    
        // 设置上级
        group_leader->setSuperior(manager);
        manager->setSuperior(boss);
    
        // 不同面额的票据统一先交给组长审批
        group_leader->handleRequest(8);
        group_leader->handleRequest(88);
        group_leader->handleRequest(888);
        group_leader->handleRequest(8888);
    
        delete group_leader;
        delete manager;
        delete boss;
        system("pause");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    输出:

    Active code page: 65001
    张组长处理了该票据, 票据面额:8.000000
    张组长无权处理, 转交上级...
    王经理处理了该票据, 票据面额:88.000000
    张组长无权处理, 转交上级...
    王经理无权处理, 转交上级...
    李老板处理了该票据, 票据面额:888.000000
    张组长无权处理, 转交上级...
    王经理无权处理, 转交上级...
    无人有权限处理该票据, 票据金额:0.000000
    Press any key to continue . . .
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    Linux:磁盘情况查询+磁盘情况的工作使用指令(内含使用实例)
    SpringBoot中“@SpringBootApplication“自动配置原理《第七课》
    MFC CList<CRect, CRect&> m_listRect;的用法
    客服快捷回复语
    好用又方便的浏览器主页,整合丰富资源,功能很齐全
    【牛客 - 剑指offer】JZ53 数字在升序数组中出现的次数 Java实现
    【LeetCode】在非有序数组中使用二分
    【Java 进阶篇】深入理解SQL查询语言(DQL)
    【LeetCode144、145、94. 二叉树遍历】——递归算法、利用栈
    C语言—详解库函数中常用的字符串函数
  • 原文地址:https://blog.csdn.net/qq_45531502/article/details/126419311