责任链模式

229 阅读4分钟

先看概念🙌

概念:责任链模式是一种行为设计模式,就是我们可以构建一个处理请求的处理链,每一个处理器依次处理请求,直到该请求被处理完毕

说人话:就是你有一个请求,只需告诉一个组件,然后这个组件如果处理不了,就会传递给下一个组件,以此类推,我们不用关心请求是被谁处理的。简单说就是请求能够按照一定的顺序经过一系列处理者,直到最终被处理

image.png

优点😶‍🌫️

两个方面:

  • 可以将请求发送者和接收者解耦,就是请求发送者不需要知道是谁处理的最终结果,增强了系统的灵活性和可扩展性
  • 可以动态地添加、删除和调整处理者对象,从而灵活地构建处理链

代码重构思考😎

比如我们对列车购票接口进行重构

怎么思考重构?😭

购票之前有一系列的参数校验等规则,我们需要写一个处理器来处理请求,里面应该有一个handel方法来处理请求,然后一个方法来搞定组件之间的顺序,因为不止一个处理器,我们考虑进行一层抽象,把处理器抽象为接口😎

到这里已经成功了一半了,别急,接着往下思考🙌

那这个处理器都要实现的接口应该怎么定义的?没错,应该是处理器共有的功能,还是那两个,处理请求、定义顺序,很好👌

到这里,已经接近成功了,再思考一个能把这个接口定义死?那现在这个是购买车票的,那以后万一有其他的方面需要责任链处理呢?遇事不决,抽象一层🤣🤣🤣

再往上走一层,让这个接口去扩展一个顶层接口,这个顶层接口定义了责任链模式需要的基本功能,然后各个接口可以去扩展其功能,好了!成功思考完成,开始写代码🐕🐕🐕

定义抽象责任链组件

  /**
   * 抽象业务责任链组件
   *
   */
  public interface AbstractChainHandler<T> extends Ordered {
  
      /**
       * 执行责任链逻辑
       *
       * @param requestParam 责任链执行入参
       */
      void handler(T requestParam);
  
      /**
       * @return 责任链组件标识
       */
      String mark();
  }
  

这段代码中定义了两个抽象方法,其中一个来执行责任链逻辑,一个来返回责任链组件标识,用来标记和区分不同的责任链处理器,然后它继承了Ordered接口,Ordered 接口中定义了一个 getOrder 方法,返回一个整数值,表示组件的执行顺序

为什么要继承ordered接口

在Spring容器中,通过自动扫描并识别实现了Ordered接口的组件,Spring会根据这些组件的执行顺序构建责任链。数值小的组件具有更高的执行优先级,因此它们会在责任链中的数值较大的组件之前执行。

定义购买车票过滤器

  /**
   * 列车购买车票过滤器
   *
   */
  public interface TrainPurchaseTicketChainFilter<T extends PurchaseTicketReqDTO> extends AbstractChainHandler<PurchaseTicketReqDTO> {
  
      @Override
      default String mark() {
          return TicketChainMarkEnum.TRAIN_PURCHASE_TICKET_FILTER.name();
      }
  }
  

这段代码定义了一个接口 TrainPurchaseTicketChainFilter,它继承了抽象业务责任链组件

<T extends PurchaseTicketReqDTO>是一个泛型约束,表明该接口的实现类必须是PurchaseTicketReqDTO及其子类

实现购票逻辑接口

  /**
   * 购票流程过滤器之验证参数必填
   *
   */
  @Component
  public class TrainPurchaseTicketParamNotNullChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> {
  
      @Override
      public void handler(PurchaseTicketReqDTO requestParam) {
          // ......
      }
  
      @Override
      public int getOrder() {
          return 0;
      }
  }
  
  /**
   * 购票流程过滤器之验证参数是否有效
   * 验证参数有效这个流程会大量交互缓存,为了优化性能需要使用 Lua。为了方便大家理解流程,这里使用多次调用缓存
   *
   */
  @Component
  @RequiredArgsConstructor
  public class TrainPurchaseTicketParamVerifyChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> {
  
      private final TrainMapper trainMapper;
      private final TrainStationMapper trainStationMapper;
      private final DistributedCache distributedCache;
  
      @Override
      public void handler(PurchaseTicketReqDTO requestParam) {
          // ......
      }
  
      @Override
      public int getOrder() {
          return 10;
      }
  }
  
  /**
   * 购票流程过滤器之验证列车站点库存是否充足
   *
   */
  @Component
  @RequiredArgsConstructor
  public class TrainPurchaseTicketParamStockChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> {
  
      private final SeatMarginCacheLoader seatMarginCacheLoader;
      private final DistributedCache distributedCache;
  
      @Override
      public void handler(PurchaseTicketReqDTO requestParam) {
          // ......
      }
  
      @Override
      public int getOrder() {
          return 20;
      }
  }
  
  /**
   * 购票流程过滤器之验证乘客是否重复购买
   *
   */
  @Component
  @RequiredArgsConstructor
  public class TrainPurchaseTicketRepeatChainHandler implements TrainPurchaseTicketChainFilter<PurchaseTicketReqDTO> {
  
      @Override
      public void handler(PurchaseTicketReqDTO requestParam) {
          // ......
      }
  
      @Override
      public int getOrder() {
          return 30;
      }
  }

总结

可以看到,最终的实现购票逻辑的接口需要实现TrainPurchaseTicketChainFilter购买车票过滤器接口、

TrainPurchaseTicketChainFilter则需要继承AbstractChainHandler接口,是一个层层继承的关系

由抽象到具体一步步细分,从而来实现业务逻辑,实际使用中可以直接把对应的请求参数丢给责任链处理器去完成

责任链模式相对来说不是难理解,只要稍微用心整理一下就会豁然开朗💕💕💕