您现在的位置是:亿华云 > IT科技类资讯

设计模式之责任链模式

亿华云2025-10-03 02:13:26【IT科技类资讯】0人已围观

简介简介定义:给多个对象处理请求的机会,减少请求的发送者与接受者之间的耦合。将接受对象链接起来,在链中传递请求,直到有一个对象处理这个请求。速记:责任传递案例:财务报销、击鼓传花、SentinelCtSp

简介

定义:给多个对象处理请求的设计机会,减少请求的模式模式发送者与接受者之间的耦合。将接受对象链接起来,任链在链中传递请求,设计直到有一个对象处理这个请求。模式模式 

速记:责任传递 

案例:财务报销、任链击鼓传花、设计Sentinel(CtSph.java)、模式模式Zookeeper、任链Nacos

我考虑对创建订单的设计流程通过责任链模式的方式进行重构,先来看看我创建订单的模式模式流程。

创建订单 -> 消耗优惠券 -> 发货 -> 返利

环境介绍:

jdk 1.8 ,任链 spring 5.2.x

代码实现

代码实现如下图所示,通过 AbstractOrderHandler 定义抽象的设计接口,规范 Handler 的模式模式行为,在我的任链场景下有 4 个 Handler : 1、CreateOrderHandler 创建订单。2、UseCouponOrderHandler 使用优惠券 3、GoodsDeliverOrderHandler 商品发货 4、RebateOrderHandler 营销返现 通过这样的设计我们就可以巧妙的,将繁杂的流程,进行水平拆分为 Handler ,云服务器提供商将之前的 BIG Method ,拆分成了一个可以复用的低耦合的类文件。下面是一个类的示意图:

定义抽象方法

AbstractOrderHandler 定义如下,主要是有两个作用,定义 doHandle 抽象方法,以及为后期按照类型区分 Handler 业务的的 getTypeEnum 方法。

public abstract class AbstractOrderHandler {      /**      * 区分类型      *      * @return      */     protected abstract OrderTypeEnum getTypeEnum();     /**      * 核心处理      *      * @param context 上下文      * @param args    拓展参数      */     public void doHandle(OrderHandleContext context,                          OrderHandlerChain chain, Object... args) {          // 我是否可以处理         if (Objects.isNull(getTypeEnum()) ||              Objects.equals(context.getTypeEnum(), getTypeEnum())) {              // 让我来处理             doHandle(context, args);         }         // 我处理完了,交给下家         chain.handle(context, args);     }     /**      * 具体业务处理      *      * @param context      * @param args      */     protected abstract void doHandle(OrderHandleContext context, Object... args); } 

责任链的实现

具体的 Handler 实现,这里我列举了两个 Handler 的代码,分别是 CreateOrderHandler 创建订单、RebateOrderHandler 营销返利。核心逻辑即使实现 AbstractOrderHandler 接口,并且实现内部的细分逻辑。

// 创建订单 @Slf4j @Service @Order(100) public class CreateOrderHandler extends AbstractOrderHandler {      @Override     protected OrderTypeEnum getTypeEnum() {          return null;     }     @Override     protected void doHandle(OrderHandleContext context, Object... args) {          log.info("default create order ... ");         // 锁定库存         lockSku(context, args);         // 保存订单         saveOrder(context);         // 扣除库存         deductSku(context, args)     } } // 订单反现金 @Service @Slf4j @Order(200) public class RebateOrderHandler extends AbstractOrderHandler {      @Override     protected OrderTypeEnum getTypeEnum() {          return null;     }     @Override     protected void doHandle(OrderHandleContext context, Object... args) {          log.info("default rebate order ... ");     } } 

定义调用入口

OrderHandlerChain 是外部调用的入口,其实它主要的作用就是获取 AbstractOrderHandler 并且排序(即串联/编排 Handler ) 然后进行执行。源码库这里我充分使用了 Spring 的 Bean 排序功能,通过在 Handler 上面定义 @Order 注解并且传入顺序值,我们在 @Autowired 获取 List 的时候,Spring 会给我自动注入排好序的 handlerList 。

@Slf4j @Component public class OrderHandlerChain {      @Autowired     private List<AbstractOrderHandler> chain;     @Autowired     private ApplicationContext applicationContext;     public void handle(OrderHandleContext context, Object... objects) {          if (context.getPos() < chain.size()) {              AbstractOrderHandler handler = chain.get(context.getPos());             // 移动位于处理器链中的位置             context.setPos(context.getPos() + 1);             handler.doHandle(context, this, objects);         }     } } 

业务拓展

如果我的订单逻辑发生变化,需要支持汽车订单的创建和兼容。我们可以增加 Car 处理的 handler 通过指定不同 OrderTypeEnum 进行处理,如果你不想创建更多的 handler 类文件也可以通过 @Bean 来进行实现。

这里其实也是一种妥协的方式,其实和直接实现 AbstractOrderHandler 并没有什么区别,都会生成 .class 文件,只是说在开发侧来看少了一个 Java 文件而已,也会占 JVM 的 Metaspace 空间。

如下所示:

@Configuration public class CarOrderHandlers {      /**      * 汽车订单创建      *      * @return      */     @Bean(name = "createOrderByCar")     public AbstractOrderHandler createOrderByCar() {          return new CreateOrderHandler() {              @Override             protected OrderTypeEnum getTypeEnum() {                  return OrderTypeEnum.Car;             }             @Autowired             private ApplicationContext applicationContext;             @Override             protected void doHandle(OrderHandleContext context, Object... args) {                  System.out.println("car order create ....");             }         };     } } 

测试代码

测试代码如下,我们只需要传入一个 Context 对象然后调用 chain.handle 方法即可。

@Slf4j @SpringBootTest(classes = App.class) public class OrderHandlerChainTest {      @Resource     private OrderHandlerChain chain;     @Test     public void testOrderChain() {          OrderHandleContext context = new OrderHandleContext();         context.setTypeEnum(OrderTypeEnum.Car);         chain.handle(context, null);     } } 

总结

本文主要是利用了 Spring 进行排序, Bean 定义等特征,实现责任链。感觉改造过后,有一点策略 + 模板 的亿华云计算感觉。策略模式主要是运用: 多方案切换的场景对业务进行垂直路由分别处理。责任链模式主要运用:责任传递的场景对业务进行水平分段处理粒度可以说更加细一些。

其实我们 JDK8 还提供了 @FunctionalInterface 函数接口,我们也可以将 AbstractOrderHandler 修改为 interface 接口,这样我们就可以通过 lambda 表达式的方式注册 Handler 其实本质都是一样的。Over!欢迎大家留言交流。

参考文章

https://www.cnblogs.com/vcmq/p/12542399.html

http://c.biancheng.net/view/1383.html

很赞哦!(38234)