zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【设计模式】责任链模式

2023-09-27 14:25:05 时间

简介

  责任链模式是行为型设计模式(关注对象之间的通信)中的一种
  责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
  在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

  设计模式参考:https://www.runoob.com/design-pattern/design-pattern-intro.html

应用场景

  Java Web中的Servlet Filter
  Spring Security中的 Filter Chain

案例Demo

  下单支付场景中,往往要经历以下几个步骤
  1.校验订单(校验订单状态,重复订单)
  2.校验支付参数(不同的支付参数校验方式不同,例如,ApplePay/PayPal/GooglePay/微信/支付宝)
  3.创建支付订单
  4.获取支付路由
  5.支付完成校验支付订单/支付凭证的状态
  6.生成支付流水记录
  7.请求订单系统,修改订单状态
  以上步骤中,如果逻辑可以被划分为七个不同的模块,每个模块按顺序串联起来,上个模块执行完成后,交给下一个模块,因此适用于责任链模式

  UML类图

 

   

public interface ContextHandler<PayContext> {

    /**
     * 处理输入的上下文数据
     *
     * @param context 处理时的上下文数据
     * @return 返回 true 则表示由下一个 ContextHandler 继续处理,返回 false 则表示处理结束
     */
    PayContext execute(PayContext context);
}
@Slf4j
@Component
public class PayOrderCreatePipeline implements ContextHandler<PayContext> {

    @Override
    public PayContext execute(PayContext payContext) {
        //....业务逻辑,省略
        return payContext
    }
}
//责任链配置
@Configuration
public class PipelineRouteConfig implements ApplicationContextAware {


    private ApplicationContext appContext;

    /**
     * 数据类型->管道中处理器类型列表 的路由
     */
    private static final
    Map<Class<PayContext>, List<Class<? extends ContextHandler<PayContext>>>> PIPELINE_ROUTE_MAP =
            new ConcurrentHashMap<>(4);

    /**
     * 在这里配置各种上下文类型对应的处理管道:键为上下文类型,值为处理器类型的列表
     */
    static {
        PIPELINE_ROUTE_MAP.put(PayContext.class, Arrays.asList(
                PayParamCheckPipeline.class,
                PaySpecialCheckPipeline.class,
                PayOrderCreatePipeline.class,
                PayChannelSurePipeline.class,
                PayRecordCreatePipeline.class,
                PayRoutePipeline.class,
                AfterPayPipeline.class
                //.....其他管道
        ));
    }

    /**
     * 在 Spring 启动时,根据路由表生成对应的管道映射关系,
     * PipelineExecutor 从这里获取处理器列表
     */
    @Bean("routers")
    public Map<Class<PayContext>, List<? extends ContextHandler<PayContext>>> getHandlerPipelineMap() {
        return PIPELINE_ROUTE_MAP.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, this::toPipeline));
    }

    /**
     * 根据给定的管道中 ContextHandler 的类型的列表,构建管道
     */
    private List<? extends ContextHandler<PayContext>> toPipeline(
            Map.Entry<Class<PayContext>, List<Class<? extends ContextHandler<PayContext>>>> entry) {
        return entry.getValue().stream().map(appContext::getBean).collect(Collectors.toList());
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        appContext = applicationContext;
    }

}
//责任链客户端
@Slf4j
@Component
public class PipelineExecutor {

    @Resource
    private Map<Class<PayContext>, List<? extends ContextHandler<PayContext>>> routers;

    public PayContext execute(PayContext context) {
        Asserts.notNull(context, "参数上下文不能为空");
        Class<? extends PayContext> clazz = context.getClass();
        List<? extends ContextHandler<PayContext>> pipelines = routers.get(clazz);
        if (CollectionUtils.isEmpty(pipelines)) {
            log.info("==========>管道为空", clazz.getSimpleName());
            throw new PayException(RetCode.ERROR);
        }
        PayContext _context = context;
        for (ContextHandler<PayContext> handler : pipelines) {
            _context = handler.execute(context);
        }
        return _context;
    }
}
//请求参数上下文
//根据实际业务封装,用于在责任链之间传递
@Data
@Builder
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class PayContext {

    /**
     * 支付请求参数
     */
    private OrderPayRequest orderPayRequest;
    /**
     * 订单信息
     */
    private OrderInfo orderInfo;
    /**
     * 支付记录
     */
    private PayRecordInfo payRecordInfo;
    /**
     * 通道支付信息
     */
    private ChannelInfo channelInfo;
    /**
     * APP信息
     */
    private AppInfo appInfo;
    /**
     * 渠道支付请求参数
     */
    private ChannelPayRequest channelPayRequest;
    /**
     * 渠道支付响应
     */
    private ChannelPayResponse channelPayResponse;
    /**
     * 支付响应VO
     */
    private OrderPayVO orderPayVO;
    /**
     * 请求头
     */
    private HeaderServerInput header;

}