• 【一起学设计模式】状态模式+装饰器模式+简单工厂模式实战:(一)提交个订单我到底经历了什么鬼?


    前言

    之前在我的博客(一枝花算不算浪漫)中已经更新过两篇设计模式相关的内容

    上面内容都是基于真实业务场景精简后的设计(工作中真实场景使用到的)。

    之前为了学习设计模式,看过网上很多相关博客讲解,大都是画下UML类图,举例几个毫不相干的demo,看了几遍仍然是云里雾里。

    因为自己现在做的项目就是属于B2C的商城,项目中使用到了大量的设计模式,所以这里精简真实的业务场景,将核心的业务代码抽离出来。代码不涉及任何公司信息,所有敏感信息都已屏蔽,代码只用作学习交流使用。

    业务场景

    一图流,首先看下提交订单 我们抽象出的一些场景:

    17C4F70C-E159-4AD8-B394-232A54F52F01.png

    订单中心:
    1、订单中心创建订单
    2、订单状态流转(状态模式)
    3、记录操作日志(装饰器模式+简单工厂模式)
    4、订单中心通知 库存中心更新库存

    调度中心:
    1、库存中心更新本地库存(使用命令模式+模板方法模式+工厂模式)
    这个上讲已经说过:【一起学设计模式】命令模式+模板方法+工厂方法实战: 如何优雅的更新商品库存...
    2、将更新库存数据放到消息中,调度中心消费消息(中介模式)
    3、放入消息队列中,判断队列是否放满了,如果放满了需要建立离线存储(备忘录模式)
    4、异步监听消息处理结果(观察者模式)

    这个模型应该很简单,我们来一步步拆解 一步步代码分析

    订单状态流转 + 操作日志记录

    代码实现

    1. 订单中心提交订单操作

      /**
      * 订单状态管理器
      */
      @Autowired
      private LoggedOrderStateManager orderStateManager;
      
      public OrderInfoDTO save(OrderInfoDTO order) throws Exception {
          // 检查库存是否充足
          if(!isStockEnough(order)) {
              return order;
          }
      
          // 将订单信息保存到本地数据库
          saveOrder(order);
          // 订单状态流转
          orderStateManager.create(order); 
      
          // other logic
          return order;
      }
      
    2. 订单状态管理器

      /**
       * 会自动记录日志的订单状态管理器
       * @author wangmeng
       *
       */
      @Component
      public class LoggedOrderStateManager implements OrderStateManager {
      
          /**
           * 订单状态管理器
           */
          @Autowired
          private OrderStateManagerImpl orderStateManager;
      
          /**
           * 订单操作日志DAO组件
           */
          @Autowired
          private OrderOperateLogDAO orderOperateLogDAO;
      
          /**
           * 订单操作内容工厂
           */
          @Autowired
          private OrderOperateLogFactory orderOperateLogFactory;
      
          @Override
          public void create(OrderInfoDTO order) throws Exception {
              orderStateManager.create(order); 
              orderOperateLogDAO.save(orderOperateLogFactory.get(order, OrderOperateType.CREATE_ORDER));      
          }
      
          @Override
          public Boolean canCancel(OrderInfoDTO order) throws Exception {
              return orderStateManager.canCancel(order);
          }
      
          @Override
          public void cancel(OrderInfoDTO order) throws Exception {
              orderStateManager.cancel(order); 
              orderOperateLogDAO.save(orderOperateLogFactory.get(order, OrderOperateType.CANCEL_ORDER)); 
          }
      }
      
    3. 日志操作工厂

      /**
       * 订单操作内容工厂
       * @author wangmeng
       *
       */
      @Component
      public class OrderOperateLogFactory {
      
          /**
           * 日期辅助组件
           */
          @Autowired
          private DateProvider dateProvider;
      
          /**
           * 获取订单操作内容
           * @param operateType 订单操作类型
           * @return 订单操作内容
           */
          public OrderOperateLogDO get(OrderInfoDTO order, Integer operateType) throws Exception {
              String operateContent = null;
      
              if(OrderOperateType.CREATE_ORDER.equals(operateType)) {
                  operateContent = "完成订单创建,订单编号为:" + order.getOrderNo(); 
              } else if(OrderOperateType.CANCEL_ORDER.equals(operateType)) {
                  operateContent = "取消订单,订单编号为:" + order.getOrderNo();
              } else if(OrderOperateType.PAY_ORDER.equals(operateType)) {
                  operateContent = "支付订单,订单编号为:" + order.getOrderNo() + ",支付金额为:" + order.getPayableAmount();
              } else if(OrderOperateType.GOODS_DELIVERY.equals(operateType)) {
                  operateContent = "已经将订单中的商品进行发货"; 
              } else if(OrderOperateType.CONFIRM_RECEIPT.equals(operateType)) {
                  operateContent = "完成确认收货"; 
              } else if(OrderOperateType.APPLY_RETURN_GOODS.equals(operateType)) {
                  operateContent = "申请退货"; 
              } else if(OrderOperateType.RETURN_GOODS_REJECTED.equals(operateType)) {
                  operateContent = "退货申请审核不通过"; 
              } else if(OrderOperateType.RETURN_GOODS_APPROVED.equals(operateType)) {
                  operateContent = "退货申请审核已通过"; 
              } else if(OrderOperateType.SEND_OUT_RETURN_GOODS.equals(operateType)) {
                  operateContent = "寄送退货商品"; 
              } else if(OrderOperateType.CONFIRM_RETURN_GOODS_RECEIPT.equals(operateType)) {
                  operateContent = "确认收到退货商品"; 
              } else if(OrderOperateType.FINISHED_RETURN_GOODS_INPUT.equals(operateType)) {
                  operateContent = "完成退货商品入库"; 
              } else if(OrderOperateType.FINISHED_RETURN_GOODS_REFUND.equals(operateType)) {
                  operateContent = "完成退款"; 
              }     
      
              OrderOperateLogDO log = create(order, operateType, operateContent);
              return log;
          }
      
          /**
           * 创建订单操作日志
           * @param operateType 订单操作类型
           * @param operateContent 订单操作内容
           * @return 订单操作日志
           * @throws Exception
           */
          private OrderOperateLogDO create(OrderInfoDTO order ,
                  Integer operateType, String operateContent) throws Exception {
              OrderOperateLogDO log = new OrderOperateLogDO();
      
              log.setOrderInfoId(order.getId()); 
              log.setOperateType(operateType);
              log.setOperateContent(operateContent); 
              log.setGmtCreate(new Date());
              log.setGmtModified(new Date()); 
              return log;
          }
      
      }
      
    4. 订单状态流转
      我们只列出来订单create和cacel两种状态,因为状态流转时要判断当前状态是否可以流转到下一个状态,所以这里还有一个canCancel方法。

      /**
       * 订单状态管理器接口
       * @author wangmeng
       *
       */
      interface OrderStateManager {
      
          /**
           * 创建订单
           * @param order 订单
           * @throws Exception
           */
          void create(OrderInfoDTO order) throws Exception;
      
          /**
           * 订单能否执行取消操作
           * @param order 订单
           * @return 能否执行取消操作
           * @throws Exception
           */
          Boolean canCancel(OrderInfoDTO order) throws Exception;
      
          /**
           * 执行取消订单操作
           * @param order 订单
           * @throws Exception
           */
          void cancel(OrderInfoDTO order) throws Exception;
      
          // 这里还会有更多的订单状态:支付、确认收货、发货、退货等等状态流转
      }
      
    5. OrderStateManager实现类

      /**
       * 订单状态管理器
       * @author wangmeng
       *
       */
      @Component
      public class OrderStateManagerImpl implements OrderStateManager {
      
          /**
           * 已取消状态
           */
          @Autowired
          private CanceledOrderState canceledOrderState;
      
          /**
           * 待付款状态
           */
          @Autowired
          private WaitForPayOrderState waitForPayOrderState;
      
          /**
           * 创建订单
           * @param order 订单
           * @throws Exception
           */
          @Override
          public void create(OrderInfoDTO order) throws Exception {
              waitForPayOrderState.doTransition(order);
          }
      
          /**
           * 订单能否执行取消操作
           * @param order 订单
           * @return 能否执行取消操作
           * @throws Exception
           */
          @Override
          public Boolean canCancel(OrderInfoDTO order) throws Exception {
              return getOrderState(order).canCancel(order);
          }
      
          /**
           * 执行取消订单操作
           * @param order 订单
           * @throws Exception
           */
          @Override
          public void cancel(OrderInfoDTO order) throws Exception {
              canceledOrderState.doTransition(order); 
          }
      
          /**
           * 获取订单状态组件
           * @param order 订单
           * @return 订单状态组件
           * @throws Exception
           */
          private OrderState getOrderState(OrderInfoDTO order) throws Exception {
              if(OrderStatus.WAIT_FOR_PAY.equals(order.getOrderStatus())) {
                  return waitForPayOrderState;
              } else if(OrderStatus.CANCELED.equals(order.getOrderStatus())) {
                  return canceledOrderState;
              } else if(OrderStatus.WAIT_FOR_DELIVERY.equals(order.getOrderStatus())) {
                  return waitForDeliveryOrderState;
              } else if(OrderStatus.WAIT_FOR_RECEIVE.equals(order.getOrderStatus())) {
                  return waitForReceiveOrderState;
              } else if(OrderStatus.FINISHED.equals(order.getOrderStatus())) {
                  return finishedOrderState;
              } else if(OrderStatus.WAIT_FOR_RETURN_GOODS_APPROVE.equals(order.getOrderStatus())) {
                  return waitForReturnGoodsApproveOrderState;
              }
              return defaultOrderState;
          }
      }
      

      OrderState:

      /**
       * 订单状态
       * @author wangmeng
       *
       */
      public interface OrderState {
      
          /**
           * 订单流转到当前这个状态
           * @param order 订单
           * @throws Exception
           */
          void doTransition(OrderInfoDTO order) throws Exception;
      
          /**
           * 判断当前状态下能否执行取消订单操作
           * @param order 订单
           * @return 能否执行取消订单操作
           * @throws Exception
           */
          Boolean canCancel(OrderInfoDTO order) throws Exception;
      }
      

      WaitForPayOrderState:

      /**
       * 待付款状态
       * @author wangmeng
       *
       */
      @Component
      public class WaitForPayOrderState extends AbstractOrderState {
      
          @Autowired
          public WaitForPayOrderState(DateProvider dateProvider, OrderInfoDAO orderInfoDAO) {
              super(dateProvider, orderInfoDAO);
          }
      
          @Override
          protected Integer getOrderStatus(OrderInfoDTO order) throws Exception {
              return OrderStatus.WAIT_FOR_PAY;
          }
      
          @Override
          public Boolean canPay(OrderInfoDTO order) throws Exception {
              return true;
          }
      
          @Override
          public Boolean canCancel(OrderInfoDTO order) throws Exception {
              return true;
          }
      }
      

      AbstractOrderState:

      	
      /**
       * 订单状态的抽象基类
       * @author wangmeng
       *
       */
      public abstract class AbstractOrderState implements OrderState {
      
          /**
           * 订单管理DAO组件
           */
          protected OrderInfoDAO orderInfoDAO;
      
          public AbstractOrderState(OrderInfoDAO orderInfoDAO) {
              this.orderInfoDAO = orderInfoDAO;
          }
      
          /**
           * 订单流转到当前这个状态
           * @param order 订单
           */
          @Override
          public void doTransition(OrderInfoDTO order) throws Exception {
              Integer orderStatus = getOrderStatus(order);
              order.setOrderStatus(orderStatus);
              orderInfoDAO.updateStatus(order.getId(), orderStatus);  
          }
      
          /**
           * 获取订单状态
           * @param order 订单
           * @return 订单状态
           * @throws Exception
           */
          protected abstract Integer getOrderStatus(OrderInfoDTO order) throws Exception;
      
          /**
           * 判断当前状态下能否执行取消订单操作
           * @param order 订单
           * @return 能否执行取消订单操作
           */
          @Override
          public Boolean canCancel(OrderInfoDTO order) throws Exception {
              return false;
          }
      }
      

    总结

    上面只是讲了 订单中心提交订单中使用了状态模式简单工厂模式装饰器模式

    状态模式:OrderStat + OrderStateManager等
    简单工厂模式:OrderOperateLogFactory
    装饰器模式:LoggedOrderStateMananger

    其中LoggedOrderStateMananger实现了OrderStateManager接口,增强了create、cancel、pay等方法的实现,添加了记录日志的功能,使得状态流转后 可以自动记录日志的功能。

    这里只是将精简后的代码提供出来,我相信认真看一下还是很易懂的,后面还有提交订单 后面的一些流程,会单独在开一片文章来讲解,敬请期待。

    申明

    本文章首发自本人博客:https://www.cnblogs.com/wang-meng 和公众号:壹枝花算不算浪漫,如若转载请标明来源!

    感兴趣的小伙伴可关注个人公众号:壹枝花算不算浪漫

    22.jpg

  • 相关阅读:
    所谓幸福
    kobuki 红外自动回充源码原理分析
    《SLAM机器人基础教程》第三章 单片机与STM32:电机码盘实现里程计实验
    《SLAM机器人基础教程》第三章 单片机与STM32:PWM电机转动实验
    《SLAM机器人基础教程》第三章 单片机与STM32:超声测距实验
    《SLAM机器人基础教程》第三章 单片机与STM32:ADC与电压检测实验
    《SLAM机器人基础教程》第三章 单片机与STM32:碰撞传感器实验
    《SLAM机器人基础教程》第三章 单片机与STM32:定时器实验
    《SLAM机器人基础教程》第三章 单片机与STM32:滴答延时实验使用SysTick实现时间戳
    《SLAM导航机器人基础》第三章:单片机与STM32:串口Printf打印实验
  • 原文地址:https://www.cnblogs.com/wang-meng/p/12038619.html
Copyright © 2020-2023  润新知