在 Tom 商店-基于策略模式实现订单创建 一文中我们介绍了基于策略模式来实现不同类型的订单创建流程。同样,不同类型的订单的取消逻辑也有所不同,而对于取消订单的公共逻辑部分我们则抽取到抽象类中实现,对于具体的取消逻辑则有各自的子类去实现,这里我们使用了模板方法模式实现。为了流程的连贯,我们这里同时也使用到了策略模式实现动态切换不同类型的取消订单实现类。
首先,我们先定义如下策略接口 CancelOrderService:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public interface CancelOrderService { Integer getCancelOrderType () ; void cancelOrder (CancelOrderRequest request, OrderDTO orderDTO) ; }
接着定义普通订单和虚拟订单的订单取消策略实现,具体如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 @Service public class CancelNormalOrderOrderServiceImpl implements CancelOrderService { @Override public Integer getCancelOrderType () { return OrderTypeEnum.NORMAL.val(); } @Override public void cancelOrder (CancelOrderRequest request, OrderDTO orderDTO) { } } @Service public class CancelVirtualOrderOrderServiceImpl implements CancelOrderService { @Override public Integer getCancelOrderType () { return OrderTypeEnum.VIRTUAL.val(); } @Override public void cancelOrder (CancelOrderRequest request, OrderDTO orderDTO) { } }
我们实现如下策略工厂,其中 getCancelOrderService 支持根据传入的订单类型 orderType 获取到 CancelNormalOrderOrderServiceImpl 或者 CancelVirtualOrderOrderServiceImpl,其原理是策略工厂 CancelOrderServiceFactory 实现 InitializingBean 接口并重写了 afterPropertiesSet,以实现从 IOC 容器中获取到 CancelOrderService 策略接口的实现类并存入到 cancelServiceMap 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 @Component public class CancelOrderServiceFactory implements InitializingBean { @Autowired private List<CancelOrderService> cancelOrderServices; private Map<Integer, CancelOrderService> cancelServiceMap = new HashMap<>(); @Override public void afterPropertiesSet () { if (CollectionUtil.isNotEmpty(cancelOrderServices)) { for (CancelOrderService service : cancelOrderServices) { cancelServiceMap.put(service.getCancelOrderType(), service); } } } public CancelOrderService getCancelOrderService (Integer orderType) { return cancelServiceMap.get(orderType); } }
我们可以使用如下代码动态调用不同类型的订单取消 service:
1 2 3 4 5 6 @Test public void cancelOrder () { CancelOrderRequest request = new CancelOrderRequest(); OrderDTO orderDTO = getOrderDTO(request); cancelOrderServiceFactory.getCancelOrderService(orderDTO.getOrderType()).cancelOrder(request, orderDTO); }
下面我们再讲解订单取消中涉及到的模板方法模式的使用,首先定义如下抽象类,executeCancel 是不同类型的订单取消的公共入口,该方法调用了模板方法 execute,注意该方法并没有实现,而只是提供了方法的定义。在调用模板方法 execute 之前,我们可以调用所有订单类型订单取消的公共逻辑,例如订单状态为待支付时,同一调用 rollbackIfOnUnpaid 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public abstract class AbsCancelOrderService { protected void executeCancel (CancelOrderRequest request, OrderDTO orderDTO) { Integer orderStatus = orderDTO.getOrderStatus(); if (Objects.equals(orderStatus, OrderStatusEnum.PREPAY)) { rollbackIfOnUnpaid(request, orderDTO); return ; } execute(request, orderDTO); } protected abstract void execute (CancelOrderRequest request, OrderDTO orderDTO) ; protected void rollbackIfOnUnpaid (CancelOrderRequest request, OrderDTO orderDTO) { } }
接着我们只需让 CancelNormalOrderOrderServiceImpl 和 CancelVirtualOrderOrderServiceImpl 类继承 AbsCancelOrderService 并重写 execute,并让 cancelOrder 调用父类的 executeCancel 方法即可。如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 @Service public class CancelNormalOrderOrderServiceImpl extends AbsCancelOrderService implements CancelOrderService { @Override protected void execute (CancelOrderRequest request, OrderDTO orderDTO) { System.out.println("执行普通订单取消" ); } @Override public Integer getCancelOrderType () { return OrderTypeEnum.NORMAL.val(); } @Override public void cancelOrder (CancelOrderRequest request, OrderDTO orderDTO) { executeCancel(request, orderDTO); } } @Service public class CancelVirtualOrderOrderServiceImpl extends AbsCancelOrderService implements CancelOrderService { @Override protected void execute (CancelOrderRequest request, OrderDTO orderDTO) { System.out.println("执行虚拟订单取消" ); } @Override public Integer getCancelOrderType () { return OrderTypeEnum.VIRTUAL.val(); } @Override public void cancelOrder (CancelOrderRequest request, OrderDTO orderDTO) { execute(request, orderDTO); } }