基于C++的《Head First设计模式》笔记——责任链模式

目录

一.专栏简介

二.责任链模式概念

三.请假审批案例和代码

四.责任链的优点

五.责任链的用途和缺点


一.专栏简介

本专栏是我学习《head first》设计模式的笔记。这本书中是用Java语言为基础的,我将用C++语言重写一遍,并且详细讲述其中的设计模式,涉及是什么,为什么,怎么做,自己的心得等等。希望阅读者在读完我的这个专题后,也能在开发中灵活且正确的使用,或者在面对面试官时,能够自信地说自己熟悉常用设计模式。

本章将开始**责任链模式(Chain of Responsibility Pattern)**的学习。

二.责任链模式概念

通过责任链模式,你可以创建一个对象链来检查请求。每个对象依次检查请求,处理它或者将它传给链中的下一个对象。

当你要把处理请求的机会给予多于一个的对象时,使用责任链模式。

模式结构:

  • Handler(抽象处理者):定义处理请求的接口,包含指向后继处理者的引用。

  • ConcreteHandler(具体处理者):实现处理接口,判断自身能否处理请求,能则处理,不能则转发给后继者。

  • Client(客户端):创建责任链,并发起请求。

下面通过在公司中请假审批的流程为例子来说明。

三.请假审批案例和代码

以 "请假审批流程" 为例(符合真实业务场景,更易理解):

  • 请假 1 天及以内:小组长审批

  • 请假 2-3 天:部门经理审批

  • 请假 4 天及以上:总经理审批

我们首先用LeaveRequest类封装请假请求 ,其中包含请假人和请假天数以及相应的get方法;然后是一个抽象类Approver表示审批者的基类 ,包含审批者和指向后继审批者的指针,也就是审批者们是一个单链表的数据结构,并提供设置下一个审批者和审批请假的函数,后者是纯虚函数。然后是具体处理者们 ,分别是小组长,部门经理和总经理,它们继承抽象类Approver,然后重写实现approve()方法,这个方法中判断这个请假条是否自己处理,如果不是则传给单链表的下一个审批者,如果走到单链表的末尾则表示请假失败。

代码如下:

chainOfResponsibilityPattern.h:

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

// 请假请求(封装请求数据)
class LeaveRequest 
{
public:
    LeaveRequest(string name, int days) : m_name(name), m_days(days) 
    {}
    string getName() const { return m_name; }
    int getDays() const { return m_days; }
private:
    string m_name;  // 请假人
    int m_days;     // 请假天数
};

// 1. 抽象处理者:审批者
class Approver 
{
public:
    Approver(string name) : m_name(name) 
    {}
    // 设置后继审批者(构建责任链)
    void setNextApprover(Approver* next) { m_nextApprover = next; }
    // 抽象审批方法(核心)
    virtual void approve(LeaveRequest* request) = 0;
    virtual ~Approver() = default;
protected:
    string m_name;                          // 审批者名称
    Approver* m_nextApprover = nullptr;     // 后继审批者
};

// 2. 具体处理者1:小组长(处理1天及以内请假)
class GroupLeader : public Approver 
{
public:
    GroupLeader(string name) : Approver(name) 
    {}
    void approve(LeaveRequest* request) override 
    {
        if (request->getDays() <= 1) 
        {
            // 自身能处理,直接审批
            cout << "小组长" << m_name << "审批:"
                << request->getName() << "请假" << request->getDays() << "天,批准!" << endl;
        }
        else if (m_nextApprover != nullptr) 
        {
            // 自身不能处理,转发给后继者
            cout << "小组长" << m_name << ":请假" << request->getDays()
                << "天,超出权限,转交给部门经理审批..." << endl;
            m_nextApprover->approve(request);
        }
        else 
        {
            // 无后继者,审批失败
            cout << "小组长" << m_name << ":无更高审批者,请假失败!" << endl;
        }
    }
};

// 2. 具体处理者2:部门经理(处理2-3天请假)
class DepartmentManager : public Approver 
{
public:
    DepartmentManager(string name) : Approver(name) 
    {}
    void approve(LeaveRequest* request) override 
    {
        if (request->getDays() >= 2 && request->getDays() <= 3) 
        {
            cout << "部门经理" << m_name << "审批:"
                << request->getName() << "请假" << request->getDays() << "天,批准!" << endl;
        }
        else if (m_nextApprover != nullptr) 
        {
            cout << "部门经理" << m_name << ":请假" << request->getDays()
                << "天,超出权限,转交给总经理审批..." << endl;
            m_nextApprover->approve(request);
        }
        else 
        {
            cout << "部门经理" << m_name << ":无更高审批者,请假失败!" << endl;
        }
    }
};

// 2. 具体处理者3:总经理(处理4天及以上请假)
class GeneralManager : public Approver 
{
public:
    GeneralManager(string name) : Approver(name) 
    {}
    void approve(LeaveRequest* request) override 
    {
        if (request->getDays() >= 4) 
        {
            cout << "总经理" << m_name << "审批:"
                << request->getName() << "请假" << request->getDays() << "天,批准!" << endl;
        }
        else
        {
            // 总经理是最终审批者,无后继者
            cout << "总经理" << m_name << ":请假天数不符合权限范围,审批失败!" << endl;
        }
    }
};

UML类图

main.cpp:(客户端代码)

cpp 复制代码
#include "chainOfResponsibilityPattern.h"

// 客户端代码
int main() 
{
    // 1. 创建各审批者
    Approver* groupLeader = new GroupLeader("张三");
    Approver* deptManager = new DepartmentManager("李四");
    Approver* genManager = new GeneralManager("王五");

    // 2. 构建责任链:小组长 → 部门经理 → 总经理
    groupLeader->setNextApprover(deptManager);
    deptManager->setNextApprover(genManager);

    // 3. 发起不同的请假请求
    LeaveRequest* req1 = new LeaveRequest("小明", 1);  // 小组长处理
    LeaveRequest* req2 = new LeaveRequest("小红", 3);  // 部门经理处理
    LeaveRequest* req3 = new LeaveRequest("小刚", 5);  // 总经理处理

    // 4. 从链头(小组长)提交请求
    groupLeader->approve(req1);
    cout << "------------------------" << endl;
    groupLeader->approve(req2);
    cout << "------------------------" << endl;
    groupLeader->approve(req3);

    // 释放资源
    delete req1;
    delete req2;
    delete req3;
    delete groupLeader;
    delete deptManager;
    delete genManager;

    return 0;
}

运行结果:

可以看到,请假条被正确的审批处理

四.责任链的优点

  • 解耦请求的发送者和接收者。

  • 允许你通过改变链的成员或次序,动态地添加或移除责任。

  • 单一职责原则:每个审批者只处理自己权限内的逻辑,无需关心其他流程,同时避免多层 if-else,代码可读性和可维护性提升。;

  • 开闭原则:新增审批级别(比如总监审批)时,只需新增一个具体处理者类,无需修改原有代码。

五.责任链的用途和缺点

  • 经常用在窗体系统中,处理鼠标点击和键盘事件。Qt底层的鼠标事件和键盘事件也是这样的。

  • 并不保证请求一定会被执行,如果没有对象处理它,可能会掉到链的末尾(这可以是优点或缺点)。

  • 运行时可能会难以观察和调试。

  • 性能开销:如果责任链过长,请求需要遍历整个链路,会有一定的性能损耗;

  • 循环引用风险:如果责任链构建错误出现环(比如总经理的后继又指回了小组长),会导致请求死循环。

相关推荐
yunyun321232 小时前
嵌入式C++驱动开发
开发语言·c++·算法
左左右右左右摇晃2 小时前
Java笔记 —— 值传递与“引用传递”
java·开发语言·笔记
ljt27249606612 小时前
Flutter笔记--事件处理
笔记·flutter
Amnesia0_02 小时前
类型转换和特殊类
开发语言·c++
飞鸟真人2 小时前
使用netty4写一个UDP的echo服务(笔记)
笔记
格林威2 小时前
C++ 工业视觉实战:Bayer 图转 RGB 的 3 种核心算法(邻域平均、双线性、OpenCV 源码级优化)
开发语言·c++·人工智能·opencv·算法·计算机视觉·工业相机
2401_851272992 小时前
C++中的模板方法模式
开发语言·c++·算法
2401_894241922 小时前
C++中的策略模式进阶
开发语言·c++·算法
.select.3 小时前
C++ 右值引用
开发语言·c++