前言
之前在我的博客(一枝花算不算浪漫)中已经更新过两篇设计模式相关的内容
- 【一起学设计模式】策略模式实战一:基于消息发送的策略模式实战
- 【一起学习设计模式】策略模式实战二:配合注解 干掉业务代码中冗余的if else...
- 【一起学设计模式】访问者模式实战:权限管理树删节点操作
- 【一起学设计模式】命令模式+模板方法+工厂方法实战: 如何优雅的更新商品库存...
上面内容都是基于真实业务场景精简后的设计(工作中真实场景使用到的)。
之前为了学习设计模式,看过网上很多相关博客讲解,大都是画下UML类图,举例几个毫不相干的demo,看了几遍仍然是云里雾里。
因为自己现在做的项目就是属于B2C的商城,项目中使用到了大量的设计模式,所以这里精简真实的业务场景,将核心的业务代码抽离出来。代码不涉及任何公司信息,所有敏感信息都已屏蔽,代码只用作学习交流使用。
业务场景
一图流,首先看下提交订单 我们抽象出的一些场景:
订单中心:
1、订单中心创建订单
2、订单状态流转(状态模式)
3、记录操作日志(装饰器模式+简单工厂模式)
4、订单中心通知 库存中心更新库存
调度中心:
1、库存中心更新本地库存(使用命令模式+模板方法模式+工厂模式)
这个上讲已经说过:【一起学设计模式】命令模式+模板方法+工厂方法实战: 如何优雅的更新商品库存...
2、将更新库存数据放到消息中,调度中心消费消息(中介模式)
3、放入消息队列中,判断队列是否放满了,如果放满了需要建立离线存储(备忘录模式)
4、异步监听消息处理结果(观察者模式)
这个模型应该很简单,我们来一步步拆解 一步步代码分析
订单状态流转 + 操作日志记录
代码实现
-
订单中心提交订单操作
/** * 订单状态管理器 */ @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; }
-
订单状态管理器
/** * 会自动记录日志的订单状态管理器 * @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)); } }
-
日志操作工厂
/** * 订单操作内容工厂 * @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; } }
-
订单状态流转
我们只列出来订单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; // 这里还会有更多的订单状态:支付、确认收货、发货、退货等等状态流转 }
-
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 和公众号:壹枝花算不算浪漫,如若转载请标明来源!
感兴趣的小伙伴可关注个人公众号:壹枝花算不算浪漫