设计模式讲解02—责任链模式(Chain)

1. 概述

定义 责任链模式是一种行为型模式,在这个模式中,通常创建了一个接收者对象的链来处理请求,该请求沿着链的顺序传递。直到有对象处理该请求为止,从而达到解耦请求发送者和请求处理者的目的。

解释 **:**责任链模式通过将多个处理器(处理对象)以链式结构连接起来,使得请求沿着这条链传递,直到有一个处理器处理该请求为止。责任链模式允许多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。

⭐什么是行为型模式?

答:行为型模式主要用于描述对类或对象怎样交互和怎样分配职责。行为型模式 (Behavioral Pattern) 是对 在不 同的对象之间划分责任和算法的抽象化

2. 优缺点

优点:

  1. 降低耦合度:请求发送者和接收者都没有对方的明确信息,而是通过抽象处理器来链接。实现了请求的发送者和处理者之间的解耦。
  2. 灵活性:可以动态地增加或删除处理器,方便扩展和维护。
  3. 易于实现:在责任链模式中,每个具体的处理器只需要实现自己的功能即可,不需要知道整个请求链的存在,这样更加容易实现其功能。

缺点:

  1. 不能保证请求一定会被处理:在责任链模式中,由于请求的处理是由多个对象负责的,所以不能保证请求一定会被处理,存在由于漏洞导致请求无响应的风险。
  2. 性能问题:在应用责任链模式时需要控制链中的处理器数量,过多的处理器会导致处理时间增加,从而影响系统性能。
  3. 调试困难:责任链模式中的处理器是动态组合的,处理逻辑较为复杂,因此需要进行详细的测试和调试。

3. 使用场景

3.1. 应用实例

  1. 请假申请流程:公司内部的请假申请一般需要经过多级审批,每个审批者的职责不同,可以通过责任链模式实现申请者与处理者之间的解耦,让申请者的请求依次经过各个处理者的处理,直到最终得到审批结果。
  2. 商品退换货:在线商场中,如果用户需要对商品进行退换货,涉及到订单创建、退货申请、快递配送等诸多步骤,这些步骤可以通过责任链模式实现,让每个处理者负责自己的任务,将责任链串接起来,以便完成整个退换货流程。
  3. 请求处理中心:当一个请求需要经过多个处理节点进行处理时,可以采用责任链模式来组织这些处理节点,使得请求在节点之间循环传递,直到得到最终结果。例如,大型网站的访问请求处理中心,就可以采用责任链模式来处理请求。
  4. 系统安全中心:当系统发生安全威胁时,可以采用责任链模式来组织安全相关的处理节点,对异常数据进行检测和拦截,保障系统安全稳定运行。

3.2. 程序场景

  1. 请求的处理顺序不确定:如果一个系统中存在多个处理请求的对象,且请求的处理可能需要先后顺序,则可以采用责任链模式,让不同的处理对象构成责任链,依次对请求进行处理。
  2. 有多个对象可需要处理请求:如果一个请求可能需要由多个对象来进行处理,而这些处理对象之间相互独立,不需要知道其他处理对象的存在,则可以采用责任链模式来实现请求的处理。
  3. 需要动态安排处理流程:如果处理流程需要动态安排,可以通过动态组合责任链节点来实现。即根据实际需求,动态安排责任链的执行顺序和强度。
  4. 需要在不影响代码整体结构的情况下,进行功能扩展:使用责任链模式可以方便地扩展系统的功能,对业务逻辑和系统结构的初始设计基本无影响,只需要添加新的处理节点、修改处理节点间的联系即可。

4. 结构⭐

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

  • 抽象处理器(Handler) 定义一个处理请求的接口,通常包含一个处理请求的方法(如 handleRequest)和一个指向下一个处理者的引用(后继者)。
  • 具体处理器(ConcreteHandler) **:**实现了抽象处理器接口,负责处理请求。如果能够处理该请求,则直接处理;否则,将请求传递给下一个处理者。
  • 客户端(Client) **:**创建处理者对象,并将它们连接成一条责任链。通常,客户端只需要将请求发送给责任链的第一个处理者,无需关心请求的具体处理过程。

5. 代码实现

5.1. 需求介绍

我们创建抽象类 AbstractLogger,带有详细的日志记录级别。然后我们创建三种类型的记录器,都扩展了 AbstractLogger。每个记录器判断消息的级别是否属于自己的级别,如果是则相应地打印出来,否则不打印并把消息传给下一个记录器。

5.2. 代码演示

  1. 创建一个抽象的记录器类(抽象处理器)

    /**

    • @Description 记录器类 ------ 抽象处理器

    • @Author gongming.Zhang

    • @Date 2024/11/6 10:39

    • @Version 1.0
      */
      public abstract class AbstractLogger {
      public static final Integer INFO = 1;
      public static final Integer DEBUG = 2;
      public static final Integer ERROR = 3;

      // protected:对本包以及不同包的子类可见
      protected Integer level;

      // 责任链中的下一个元素
      protected AbstractLogger nextLogger;

      public void setNextLogger(AbstractLogger nextLogger) {
      this.nextLogger = nextLogger;
      }

      public void logMessage(int level, String message) {
      if (this.level <= level) {
      write(message);
      }

       // 核心逻辑,链式连接多个处理器
       if (nextLogger != null) {
           nextLogger.logMessage(level, message);
       }
      

      }

      // 抽象方法,具体的处理器去实现对应的逻辑
      protected abstract void write(String message);
      }

  2. 创建扩展了该记录器抽象类的具体实现类(具体抽象类)

    /**

    • @Description 控制台日志类

    • @Author gongming.Zhang

    • @Date 2024/11/6 10:55

    • @Version 1.0
      */
      public class ConsoleLogger extends AbstractLogger {

      public ConsoleLogger(int level) {
      this.level = level;
      }

      @Override
      protected void write(String message) {
      System.out.println("Standard Console::Logger: " + message);
      }
      }

    /**

    • @Description 报错日志类

    • @Author gongming.Zhang

    • @Date 2024/11/6 10:58

    • @Version 1.0
      */
      public class ErrorLogger extends AbstractLogger {

      public ErrorLogger(int level){
      this.level = level;
      }

      @Override
      protected void write(String message) {
      System.out.println("Error Console::Logger: " + message);
      }
      }

    /**

    • @Description 文件日志类

    • @Author gongming.Zhang

    • @Date 2024/11/6 10:58

    • @Version 1.0
      */
      public class FileLogger extends AbstractLogger {

      public FileLogger(int level){
      this.level = level;
      }

      @Override
      protected void write(String message) {
      System.out.println("File::Logger: " + message);
      }
      }

  3. 创建不同类型的记录器,并赋予它们不同的错误级别,并在每个记录器中设置下一个记录器。(客户端)

    /**

    • 客户端 Client

    • @return 返回链头
      */
      private static AbstractLogger getChainOfLoggers() {
      AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
      AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
      AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);

      // 设置链路
      errorLogger.setNextLogger(fileLogger);
      fileLogger.setNextLogger(consoleLogger);

      return errorLogger;
      }

    /**

    • 测试
      */
      @Test
      void testChainDesignPatterns() {
      AbstractLogger loggerChain = getChainOfLoggers();

      loggerChain.logMessage(AbstractLogger.INFO, "This is an information");
      loggerChain.logMessage(AbstractLogger.DEBUG, "This is a debug level information.");

      loggerChain.logMessage(AbstractLogger.ERROR, "This is an error information.");
      }

结果:

Standard Console::Logger: This is an information.
File::Logger: This is a debug level information.
Standard Console::Logger: This is a debug level information.
Error Console::Logger: This is an error information.
File::Logger: This is an error information.
Standard Console::Logger: This is an error information.
相关推荐
神仙别闹14 分钟前
基于java的改良版超级玛丽小游戏
java
Dream_Snowar24 分钟前
速通Python 第三节
开发语言·python
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭38 分钟前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员
暮湫1 小时前
泛型(2)
java
超爱吃士力架1 小时前
邀请逻辑
java·linux·后端
南宫生1 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
转码的小石1 小时前
12/21java基础
java
高山我梦口香糖1 小时前
[react]searchParams转普通对象
开发语言·前端·javascript
李小白661 小时前
Spring MVC(上)
java·spring·mvc
GoodStudyAndDayDayUp2 小时前
IDEA能够从mapper跳转到xml的插件
xml·java·intellij-idea