【设计模式】——职责链模式(Chain of Responsibility Pattern)

目录

引言

一、职责链模式的基本概念

核心思想

职责链模式结构

UML图

应用场景

二、职责链模式的优点与缺点

优点

缺点

三、C++实现职责链模式

定义请求类

定义抽象处理者

定义具体处理者

客户端代码

四、总结


引言

在软件开发中,设计模式是一种被反复使用、多数人知晓、经过分类编目的、代码设计经验的总结。职责链模式(Chain of Responsibility Pattern)是其中一种重要的行为型设计模式,它允许你将请求沿着处理者链进行传递,直到其中一个处理者能够处理它为止。这种模式的主要优点在于解耦请求的发送者和接收者,使系统更加灵活和可扩展。

一、职责链模式的基本概念

核心思想

职责链模式(Chain of Responsibility Pattern)是一种行为型设计模式,它的核心思想是将请求的发送者和接收者解耦,通过创建一个对象链来传递请求,直到链中的某个对象能够处理该请求为止。这种模式允许多个对象都有机会处理这个请求,或者将这个请求传递给链中的下一个对象。

职责链模式结构

职责链模式主要包含以下几个角色:

  1. 抽象处理者(Handler):定义了一个处理请求的接口,通常包含一个抽象处理方法和一个指向下一个处理者的引用(链中的每个处理者都有一个成员变量来保存对于下一处理者的引用)。

  2. 具体处理者(Concrete Handler):实现了抽象处理者的处理方法,判断能否处理本次请求,如果可以则处理,否则将该请求转给它的后继者。

  3. 客户类(Client):创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。

UML图

应用场景

职责链模式在实际应用中有多种典型场景,以下是一些常见的应用:

  1. 审批流程:如报销审批、请假审批等,不同级别的审批人员构成责任链,依次处理请求。这种场景下,每个审批人员都可以选择是否批准请求,或者将其传递给下一个审批人员。
  2. 事件处理:在图形用户界面(GUI)开发中,事件处理机制可以采用职责链模式,将事件从用户界面传递给各种控件,以便处理用户输入。这种方式使得事件的处理更加灵活,可以动态地添加或删除事件处理器。
  3. 日志记录:不同级别的日志记录器可以组成责任链,根据日志级别决定是否记录日志以及如何记录。这种方式使得日志系统的配置更加灵活,可以根据需要动态地调整日志记录的级别和方式。
  4. 异常处理:在程序中处理异常时,可以使用职责链模式来处理不同类型的异常,以便根据异常类型采取不同的处理策略。这种方式使得异常处理更加集中和灵活,可以轻松地添加新的异常处理逻辑。
  5. 权限控制:在系统中控制用户访问权限时,可以使用职责链模式来构建权限控制链,根据用户的权限级别逐级检查并授权。这种方式使得权限控制更加灵活和可扩展,可以轻松地添加新的权限控制逻辑。
  6. HTTP请求处理:Web框架中的中间件(Middleware)可以使用职责链模式来处理HTTP请求,例如身份验证、日志记录、缓存等中间件可以依次处理请求。这种方式使得Web应用的请求处理流程更加清晰和灵活。

二、职责链模式的优点与缺点

优点

  1. 降低耦合度:职责链模式将请求的发送者和接收者解耦,发送者和接收者都不需要知道对方的明确信息,降低了系统的耦合度。

  2. 增强系统的可扩展性:可以根据需要增加新的请求处理类,满足开闭原则(对扩展开放,对修改关闭)。

  3. 增强灵活性:可以动态地改变链内的成员或者调动它们的次序,也可以动态地新增或删除责任。

  4. 简化对象之间的连接:每个对象只需保持一个指向其后继者的引用,避免了使用众多的if或if-else语句。

  5. 职责分明:每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。

缺点

  1. 不能保证每个请求一定被处理:由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。

  2. 性能问题:对于比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。

  3. 客户端复杂性:职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。

  4. 调试困难:当请求在链中传递时,可能难以跟踪请求的处理过程,增加了调试的难度。

三、C++实现职责链模式

以下是一个使用C++实现的职责链模式的示例,我们将通过模拟一个简单的请假审批系统来展示这个模式的应用。

定义请求类

首先,我们定义一个WrittenRequest类,它代表一个请假请求。

#include <iostream>
#include <string> 

// 定义请求类
class WrittenRequest {
public:
    std::string username;
    std::string content;
    int day;

    WrittenRequest(std::string username, std::string content, int day)
        : username(username), content(content), day(day) {}

    // Getters and Setters 省略 
};

定义抽象处理者

然后,我们定义一个Approver类作为抽象处理者,它包含一个指向下一个处理者的指针,并定义了处理请求的接口。


// 抽象处理者
#include <memory>  

class Approver {
protected:
    std::shared_ptr<Approver> successor;
    std::string name;

public:
    Approver(std::string name) : name(name) {}

    void setSuccessor(std::shared_ptr<Approver> successor) {
        this->successor = successor;
    }

    virtual void handle(WrittenRequest request) = 0;
};

定义具体处理者

接着,我们定义几个具体处理者类,如Director(主任)、Manager(经理)和GeneralManager(总经理),它们继承自Approver类并实现handle方法。

// 具体处理者
class Director : public Approver {
public:
    Director(std::string name) : Approver(name) {}

    void handle(WrittenRequest request) override {
        if (request.day < 3) {
            std::cout << "[" << name << "] 审批并通过了" << std::endl;
        }
        else {
            if (successor) {
                successor->handle(request);
            }
        }
    }
};

class Manager : public Approver {
public:
    Manager(std::string name) : Approver(name) {}

    void handle(WrittenRequest request) override {
        if (request.day >= 3 && request.day < 10) {
            std::cout << "[" << name << "] 审批并通过了" << std::endl;
        }
        else {
            if (successor) {
                successor->handle(request);
            }
        }
    }
};

class GeneralManager : public Approver {
public:
    GeneralManager(std::string name) : Approver(name) {}

    void handle(WrittenRequest request) override {
        if (request.day >= 10 && request.day <= 30) {
            std::cout << "[" << name << "] 审批并通过了" << std::endl;
        }
        else {
            std::cout << "请假超过30天,拒绝此申请!" << std::endl;
        }
    }
};

客户端代码

最后,我们在客户端创建处理者链,并发送请求。

int main() {
    auto director = std::make_shared<Director>("张主任");
    auto manager = std::make_shared<Manager>("李经理");
    auto generalManager = std::make_shared<GeneralManager>("王总");

    director->setSuccessor(manager);
    manager->setSuccessor(generalManager);

    WrittenRequest request("张三", "因个人原因需要请假", 15);
    // 发送请求  
    director->handle(request);

    return 0;
}

当上述程序运行时,首先会创建一个`WrittenRequest`对象,表示张三需要请假15天。然后,我们创建了三个处理者对象:`Director`(张主任)、`Manager`(李经理)和`GeneralManager`(王总),并将它们连接成一个链,其中张主任是链的起点,王总是链的终点。 在`main`函数中,我们调用了张主任的`handle`方法来处理这个请假请求。由于请假天数为15天,张主任无法直接处理(他的权限范围是小于3天),因此他会将请求传递给链中的下一个处理者——李经理。 李经理的权限范围是3天到10天,同样无法处理这个请求,因此他会继续将请求传递给王总。 王总作为链的终点,能够处理这个请求(他的权限范围是10天到30天),因此他会输出“[王总] 审批并通过了”,表示请假请求被批准。

四、总结

通过职责链模式,我们成功地将请求的发送者和接收者解耦,使得系统更加灵活和可扩展。在请假审批系统中,我们可以很容易地添加或删除处理者,而不需要修改其他处理者的代码。此外,职责链模式还允许我们动态地改变处理者的顺序,以适应不同的业务场景。 在实际应用中,职责链模式可以应用于多种场景,如日志记录、权限检查、异常处理等。通过合理地使用职责链模式,我们可以使代码更加清晰、易于维护,并提高系统的可扩展性和灵活性。

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

J^T

谢谢帅哥/美女

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值