Advertisement

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

阅读量:

目录

引言

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

核心思想

职责链模式结构

UML图

应用场景

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

优点

缺点

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

定义请求类

定义抽象处理者

定义具体处理者

客户端代码

四、总结


引言

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

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

核心思想

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

职责链模式结构

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

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

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

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

UML图

应用场景

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

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

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

优点

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

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

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

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

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

缺点

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

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

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

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

三、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 省略 
    
 };
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/of3vKbHNBPIrXhY6x8dLp1UFJlu9.png)

定义抽象处理者

然后,我们定义一个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;
    
 };
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/yRXcC6hQeNjH0G4FsMIDZrq9Ez3v.png)

定义具体处理者

接着,我们定义几个具体处理者类,如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;
    
     }
    
     }
    
 };
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/LNcYi8dGPbVBjDs5vuFTzRk7ayeJ.png)

客户端代码

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

复制代码
 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;
    
 }
    
    
    
    
    cpp
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-16/Z8aTlNHOthpUE435RcBWin1D7rz2.png)

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

四、总结

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

全部评论 (0)

还没有任何评论哟~