设计模式14:职责链模式

时间:2025-02-18 22:21:13

 系列总链接:《大话设计模式》学习记录_net 大话设计-****博客

1.概述

     职责链模式(Chain of Responsibility Pattern)是一种行为设计模式,它允许将请求沿着处理者链传递,直到有一个处理者能够处理该请求。这种模式通过避免发送者和接收者之间的直接耦合,使得多个对象都有机会处理请求,从而增强了系统的灵活性和可扩展性。每个处理者包含对其下一个处理者的引用,如果当前处理者无法处理请求,则会将请求转发给其后续的处理者。

2.结构与实现

结构:

  • Handler(抽象处理者):定义一个接口或抽象类,声明用于处理请求的方法,并维护对下一个处理者的引用。
  • ConcreteHandler(具体处理者):继承自Handler,实现处理请求的具体逻辑。如果不能处理请求,则将请求转发给下一个处理者。
  • Client(客户端):创建职责链,并向链上的第一个处理者发起请求。

实现:

参照概述的中例子,实现如下:

以银行贷款审批流程为例:

  • 定义Approver作为抽象处理者。
  • JuniorManagerMiddleManager, 和 SeniorManager作为具体处理者。
  • PurchaseRequest表示请求对象。

main.cpp:

/*********************************************
   代码说明:
    1.PurchaseRequest 类:表示一个采购请求,包含请求编号和金额。
    2.Approver 类:审批人的基类,包含一个指向下一个审批人的指针 successor,并定义了处理请求的接口 processRequest。
    3.JuniorManager、MiddleManager、SeniorManager 类:分别表示初级、中级、高级经理,继承自 Approver,并实现了 processRequest 方法,
      根据金额决定是否处理请求或交给下一个审批人。
    4.main 函数:创建了三个审批人对象,并设置了责任链。然后创建了三个采购请求,并通过初级经理开始处理这些请求。

   责任链模式:
    责任链模式允许你将请求沿着处理链传递,直到有一个对象处理它为止。在这个例子中,请求会根据金额的大小被不同的经理处理。
 ************************************************/

#include <QCoreApplication>
#include <iostream>

// 定义一个采购请求类
class PurchaseRequest {
private:
    int requestNumber;  // 请求编号
    double amount;      // 请求金额
public:
    // 构造函数,初始化请求编号和金额
    PurchaseRequest(int number, double amount): requestNumber(number), amount(amount) {}
    
    // 获取请求编号
    int getRequestNumber() const { return requestNumber; }
    
    // 获取请求金额
    double getAmount() const { return amount; }
};

// 定义一个审批人类,作为基类
class Approver {
protected:
    Approver* successor; // 指向下一个审批人的指针
public:
    // 构造函数,初始化 successor 为 nullptr
    Approver() : successor(nullptr) {}
    
    // 虚析构函数,确保派生类的析构函数被正确调用
    virtual ~Approver() {}

    // 设置下一个审批人
    void setSuccessor(Approver* successor) {
        this->successor = successor;
    }

    // 纯虚函数,处理请求的接口
    virtual void processRequest(PurchaseRequest* request) = 0;
};

// 初级经理类,继承自 Approver
class JuniorManager : public Approver {
public:
    // 处理请求的具体实现
    void processRequest(PurchaseRequest* request) override
    {
        if(request->getAmount() < 10000)
        {  // 如果金额小于 10000,初级经理可以处理
            std::cout << "Junior Manager approves request #" << request->getRequestNumber() << std::endl;
        } else if (successor != nullptr) {  // 否则交给下一个审批人处理
            successor->processRequest(request);
        }
    }
};

// 中级经理类,继承自 Approver
class MiddleManager : public Approver {
public:
    // 处理请求的具体实现
    void processRequest(PurchaseRequest* request) override
    {
        if(request->getAmount() >= 10000 && request->getAmount() < 50000)
        {  // 如果金额在 10000 到 50000 之间,中级经理可以处理
            std::cout << "Middle Manager approves request #" << request->getRequestNumber() << std::endl;
        } else if (successor != nullptr) {  // 否则交给下一个审批人处理
            successor->processRequest(request);
        }
    }
};

// 高级经理类,继承自 Approver
class SeniorManager : public Approver {
public:
    // 处理请求的具体实现
    void processRequest(PurchaseRequest* request) override
    {
        if(request->getAmount() >= 50000)
        {  // 如果金额大于等于 50000,高级经理可以处理
            std::cout << "Senior Manager approves request #" << request->getRequestNumber() << std::endl;
        } else if (successor != nullptr) {  // 否则交给下一个审批人处理
            successor->processRequest(request);
        }
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建审批人对象
    Approver* juniorManager = new JuniorManager();
    Approver* middleManager = new MiddleManager();
    Approver* seniorManager = new SeniorManager();

    // 设置责任链:初级经理 -> 中级经理 -> 高级经理
    juniorManager->setSuccessor(middleManager);
    middleManager->setSuccessor(seniorManager);

    // 创建采购请求
    PurchaseRequest request1(1, 9000);   // 金额 9000,应由初级经理处理
    PurchaseRequest request2(2, 25000);  // 金额 25000,应由中级经理处理
    PurchaseRequest request3(3, 60000); // 金额 60000,应由高级经理处理

    // 处理请求
    juniorManager->processRequest(&request1); // 初级经理处理
    juniorManager->processRequest(&request2); // 中级经理处理
    juniorManager->processRequest(&request3); // 高级经理处理

    // 释放内存
    delete juniorManager;
    delete middleManager;
    delete seniorManager;

    return a.exec();
}

运行效果:

Junior Manager approves request #1
Middle Manager approves request #2
Senior Manager approves request #3

3.应用

职责链模式适用于以下场景:

  • 当有多个对象可能处理一个请求,但具体由哪个对象处理在运行时确定。
  • 需要动态指定一组对象来处理请求,例如日志记录系统中不同级别的日志处理器。
  • 希望解耦请求的发送者和接收者,比如事件监听器或回调机制。

4.优缺点及适用环境

优点:

  •  降低耦合度:发送者无需知道请求将被哪个接收者处理,仅需将请求传递给第一个处理者即可。
  • 增强灵活性:可以动态地调整链中的处理者顺序或添加新的处理者。
  • 简化对象职责:每个处理者只关注自己能否处理请求,而不需要关心整个处理流程。 

缺点:

  •  可能导致性能问题:若没有处理者能处理请求,可能会导致不必要的遍历。
  • 调试复杂性增加:由于请求的处理路径不固定,增加了追踪错误的难度 

应用环境:

  • 当需要处理某些请求的对象集合是动态的或未知的时候。
  • 不同的请求类型需要不同的处理方式,且这些方式可以在运行时改变。
  • 希望将复杂的业务逻辑拆分为一系列独立的小步骤,以便更容易理解和管理。

      通过职责链模式,我们可以构建更加灵活、易于扩展的应用程序,尤其是在涉及多种类型的请求处理时。然而,在使用此模式时也应注意其可能带来的性能损耗和复杂性的增加。

5.举一反三

职责链模式因其灵活性和可扩展性,在许多不同的实际场景中都有广泛的应用。除了银行审批流程外,以下是几个典型的实际使用场景:

1. 日志记录系统

在日志记录系统中,可以设置不同级别的日志处理器(如DebugLogger, InfoLogger, ErrorLogger等),每个处理器负责处理特定严重级别的日志消息。如果某个处理器无法处理(即消息的严重级别不在其范围内),它会将消息传递给下一个处理器。

应用场景:日志框架通常需要支持多种输出方式(控制台、文件、数据库等)和不同的日志级别。通过职责链模式,可以根据日志级别动态决定哪个处理器来处理日志信息。


2. GUI事件处理

图形用户界面(GUI)中的事件分发机制也可以采用职责链模式。例如,当用户点击一个按钮时,事件可能首先由按钮本身处理;如果没有被处理,则继续向上层容器传播,直到找到能够处理该事件的对象。

应用场景:复杂的GUI应用中,为了确保事件能够被正确的组件处理,同时允许组件具有独立性和复用性,职责链模式提供了一种有效的解决方案。

3. Web请求过滤器


在网络应用程序中,尤其是基于Servlet的Java Web应用程序中,可以使用过滤器链(Filter Chain)来实现请求预处理或后处理。每个过滤器负责执行特定的任务(如身份验证、压缩响应等),然后决定是否将请求转发给下一个过滤器。

应用场景:在构建Web服务时,为了解耦各种横切关注点(如安全检查、性能监控等),可以使用职责链模式组织这些逻辑。


4. 异常处理

在某些编程环境中,异常处理机制可以通过职责链模式来实现。每个“异常处理器”尝试捕获并处理异常,若当前处理器不能处理,则将异常传递给下一个处理器。

应用场景:对于那些需要灵活且可配置的异常处理策略的系统来说,职责链模式可以帮助开发者轻松地添加新的异常处理逻辑而不影响现有代码。


5. 工作流引擎


在企业级工作流管理系统中,任务的执行顺序和条件判断非常复杂。通过职责链模式,可以设计出灵活的工作流定义,使得任务能够按照预定规则自动流转。

应用场景:在自动化办公软件或业务流程管理系统(BPM)中,利用职责链模式可以有效地管理和调度任务,提高工作效率。


6. 中间件架构


现代分布式系统中,中间件常常用于处理客户端和服务端之间的通信。每层中间件都可能对请求进行一些操作(如加密解密、协议转换等),然后将请求转发给下一层中间件直至到达最终的服务端。

应用场景:构建微服务架构或SOA(Service-Oriented Architecture)时,通过职责链模式可以使各服务之间的交互更加模块化和易于维护。