前言
之前在我的博客 (一枝花算不算浪漫) 中已经更新过两篇设计模式相关的内容
[一起学设计模式] 策略模式实战一: 基于消息发送的策略模式实战
[一起学习设计模式] 策略模式实战二: 配合注解 干掉业务代码中冗余的 if else...
[一起学设计模式] 访问者模式实战: 权限管理树删除节点操作
上面内容都是基于真实业务场景精简后的设计(工作中真实场景使用到的).
之前为了学习设计模式, 看过网上很多相关博客讲解, 大都是画下 UML 类图, 举例几个毫不相干的 demo, 看了几遍仍然是云里雾里.
学习设计模式只有在真正的业务场景去使用才会更好的理解其精髓. 这里举例自己工作中电商的业务场景, 然后配合一些业务功能的实现, 来学会设计模式, 使自己的代码更优雅.
业务背景
在一个电商或者进销存业务中, 我们都有库存的概念.
更新库存又分为很多种场景: 购买, 退货, 下单, 取消订单, 加购物车等等
当然, 我们之前也见过策略模式, 这种业务可以抽象为每个策略去做. 但是这里我们使用新的设计模式来尝试完成它.
命令模式 command
设置一系列的 command 命令, 我们将不同类型的库存更新逻辑, 封装了不同的库存更新命令.
命令模式还有一个很经典的场景, 就是做这个命令撤销. 如果我们在执行这个命令的过程中, 发现命令中的某个步骤失败了, 我们可以在 command 里面实现一套 cancel 的逻辑, 撤销这个命令之前做的所有操作, 对已经完成的好做执行反步骤.
模板方法模式
将一些通用的步骤抽取到抽象基类, 另外一个基于模板的模式限定了每个库存更新的过程都是一样的, 按照一样的步骤和顺序走, 很清晰. 后面如果要修改更新库存的逻辑, 或者 hi 新增一种库存更新的逻辑, 都是按照一样的步骤和顺序去走.
工厂方法模式
工厂方法模式, 就是将工厂模式和模板方法模式, 结合起来.
就是说, 可能我们需要的不是一个工厂, 不同的工厂创建不同的产品, 但是这些工厂之间有一些通用的逻辑, 可以抽取到父工厂里面去, 子工厂就专注于自己的事情就可以了.
类图
代码实现
商品库存更新命令接口
这里采用的 command 命令模式
- /**
- * 商品库存更新命令的接口
- *
- * @author wangmeng
- * @blog https://www.cnblogs.com/wang-meng/
- * @create 2019-12-05 06:42
- **/
- public interface StockUpdater {
- /**
- * 更新商品库存
- * @return 处理结果
- */
- Boolean updateGoodsStock();
- }
创建更新命令 command 的工厂接口
这里采用的是工厂方法模式
- /**
- * 库存更新命令工厂接口
- *
- * @author wangmeng
- * @blog https://www.cnblogs.com/wang-meng/
- * @create 2019-12-05 06:42
- **/
- public interface StockUpdaterFactory<T> {
- /**
- * 创建一个库存更新命令
- *
- * @param parameter 参数对象
- * @return 库存更新命令
- */
- StockUpdater create(T parameter);
- }
商品库存更新命令的抽象基类
- /**
- * 商品库存更新命令的抽象基类
- *
- * @author wangmeng
- * @blog https://www.cnblogs.com/wang-meng/
- * @create 2019-12-05 06:44
- **/
- @Slf4j
- public abstract class AbstractStockUpdater implements StockUpdater{
- /**
- * 商品库存对象集合
- */
- protected List<InventoryGoodsStock> goodsStockList;
- /**
- * 商品库存管理模块 service
- */
- protected InventoryGoodsStockService goodsStockService;
- public AbstractStockUpdater(List<InventoryGoodsStock> goodsStockList, InventoryGoodsStockService goodsStockService) {
- this.goodsStockList = goodsStockList;
- this.goodsStockService = goodsStockService;
- }
- /**
- * 更新商品库存
- * @return
- */
- @Override
- public Boolean updateGoodsStock() {
- try {
- updateSaleStockQuantity();
- updateLockedStockQuantity();
- updateSaledStockQuantity();
- updateStockStatus();
- updateGmtModified();
- executeUpdateGoodsStock();
- } catch (Exception e) {
- log.error("error", e);
- }
- return true;
- }
- /**
- * 更新商品的销售库存
- * @throws Exception
- */
- protected abstract void updateSaleStockQuantity() throws Exception;
- /**
- * 更新商品的锁定库存
- * @throws Exception
- */
- protected abstract void updateLockedStockQuantity() throws Exception;
- /**
- * 更新商品的已销售库存
- * @throws Exception
- */
- protected abstract void updateSaledStockQuantity() throws Exception;
- /**
- * 更新商品的库存状态
- */
- private void updateStockStatus() throws Exception {
- for(InventoryGoodsStock goodsStockDO : goodsStockList) {
- if(goodsStockDO.getSaleStockQuantity()> 0L) {
- goodsStockDO.setStockStatus(StockStatus.IN_STOCK);
- } else {
- goodsStockDO.setStockStatus(StockStatus.NOT_IN_STOCK);
- }
- }
- }
- /**
- * 更新商品库存的修改时间
- */
- private void updateGmtModified() throws Exception {
- Date current = new Date();
- for(InventoryGoodsStock goodsStockDO : goodsStockList) {
- goodsStockDO.setGmtModified(current);
- }
- }
- /**
- * 实际执行更新商品库存的操作
- * @throws Exception
- */
- private void executeUpdateGoodsStock() throws Exception {
- for(InventoryGoodsStock goodsStockDO : goodsStockList) {
- goodsStockService.updateById(goodsStockDO);
- }
- }
- }
抽象创建 command 的工厂类
- /**
- * @author wangmeng
- * @blog https://www.cnblogs.com/wang-meng/
- * @create 2019-12-05 06:56
- **/
- @Slf4j
- public abstract class AbstractStockUpdaterFactory<T> implements StockUpdaterFactory<T> {
- protected InventoryGoodsStockService stockService;
- public AbstractStockUpdaterFactory(InventoryGoodsStockService stockService) {
- this.stockService = stockService;
- }
- @Override
- public StockUpdater create(T parameter) {
- try {
- List<Long> goodsSkuIds = getGoodsSkuIds(parameter);
- List<InventoryGoodsStock> goodsStockDOs = createGoodsStockList(goodsSkuIds);
- return create(goodsStockDOs, parameter);
- } catch (Exception e) {
- log.error("error", e);
- }
- return null;
- }
- /**
- * 获取商品 sku id 集合
- * @param parameter 参数
- * @return 商品 sku id 集合
- * @throws Exception
- */
- protected abstract List<Long> getGoodsSkuIds(T parameter) throws Exception;
- /**
- * 创建库存更新命令
- * @param parameter 参数
- * @param goodsStockDOs 商品库存 DO 对象集合
- * @return 库存更新命令
- * @throws Exception
- */
- protected abstract StockUpdater create(
- List<InventoryGoodsStock> goodsStockDOs, T parameter) throws Exception;
- /**
- * 创建商品库存 DO 对象集合
- *
- * @param goodsSkuIds 商品 sku id 集合
- * @return 商品库存对象集合
- */
- private List<InventoryGoodsStock> createGoodsStockList(List<Long> goodsSkuIds) throws Exception {
- List<InventoryGoodsStock> goodsStocks = new ArrayList<>(goodsSkuIds.size());
- EntityWrapper<InventoryGoodsStock> wrapper = new EntityWrapper<>();
- wrapper.in("goods_sku_id", goodsSkuIds);
- List<InventoryGoodsStock> goodsStockList = stockService.selectList(wrapper);
- Map<Long, InventoryGoodsStock> stockMap = new HashMap<>();
- if (!CollectionUtils.isEmpty(goodsStockList)) {
- stockMap = goodsStockList.stream().collect(Collectors.toMap(InventoryGoodsStock::getGoodsSkuId, Function.identity()));
- }
- for (Long goodsSkuId : goodsSkuIds) {
- InventoryGoodsStock inventoryGoodsStock = stockMap.get(goodsSkuId);
- if (inventoryGoodsStock == null) {
- inventoryGoodsStock = createGoodsStock(goodsSkuId);
- // 不建议循环中操作 sql, 这里只做演示作用, 实际可以批量操作 sql
- stockService.insert(inventoryGoodsStock);
- }
- goodsStocks.add(inventoryGoodsStock);
- }
- return goodsStocks;
- }
- /**
- * 创建商品库存 DO 对象
- * @param goodsSkuId 商品 sku id
- * @return 商品库存 DO 对象
- */
- private InventoryGoodsStock createGoodsStock(Long goodsSkuId) {
- InventoryGoodsStock goodsStockDO = new InventoryGoodsStock();
- goodsStockDO.setGoodsSkuId(goodsSkuId);
- goodsStockDO.setSaleStockQuantity(0L);
- goodsStockDO.setLockedStockQuantity(0L);
- goodsStockDO.setSaledStockQuantity(0L);
- goodsStockDO.setStockStatus(StockStatus.NOT_IN_STOCK);
- goodsStockDO.setGmtCreate(new Date());
- goodsStockDO.setGmtModified(new Date());
- return goodsStockDO;
- }
- }
采购入库库存更新命令的工厂
- /**
- * @author wangmeng
- * @blog https://www.cnblogs.com/wang-meng/
- * @create 2019-12-05 06:56
- **/
- @Slf4j
- public abstract class AbstractStockUpdaterFactory<T> implements StockUpdaterFactory<T> {
- protected InventoryGoodsStockService stockService;
- public AbstractStockUpdaterFactory(InventoryGoodsStockService stockService) {
- this.stockService = stockService;
- }
- @Override
- public StockUpdater create(T parameter) {
- try {
- List<Long> goodsSkuIds = getGoodsSkuIds(parameter);
- List<InventoryGoodsStock> goodsStockDOs = createGoodsStockList(goodsSkuIds);
- return create(goodsStockDOs, parameter);
- } catch (Exception e) {
- log.error("error", e);
- }
- return null;
- }
- /**
- * 获取商品 sku id 集合
- * @param parameter 参数
- * @return 商品 sku id 集合
- * @throws Exception
- */
- protected abstract List<Long> getGoodsSkuIds(T parameter) throws Exception;
- /**
- * 创建库存更新命令
- * @param parameter 参数
- * @param goodsStockDOs 商品库存 DO 对象集合
- * @return 库存更新命令
- * @throws Exception
- */
- protected abstract StockUpdater create(
- List<InventoryGoodsStock> goodsStockDOs, T parameter) throws Exception;
- /**
- * 创建商品库存 DO 对象集合
- *
- * @param goodsSkuIds 商品 sku id 集合
- * @return 商品库存对象集合
- */
- private List<InventoryGoodsStock> createGoodsStockList(List<Long> goodsSkuIds) throws Exception {
- List<InventoryGoodsStock> goodsStocks = new ArrayList<>(goodsSkuIds.size());
- EntityWrapper<InventoryGoodsStock> wrapper = new EntityWrapper<>();
- wrapper.in("goods_sku_id", goodsSkuIds);
- List<InventoryGoodsStock> goodsStockList = stockService.selectList(wrapper);
- Map<Long, InventoryGoodsStock> stockMap = new HashMap<>();
- if (!CollectionUtils.isEmpty(goodsStockList)) {
- stockMap = goodsStockList.stream().collect(Collectors.toMap(InventoryGoodsStock::getGoodsSkuId, Function.identity()));
- }
- for (Long goodsSkuId : goodsSkuIds) {
- InventoryGoodsStock inventoryGoodsStock = stockMap.get(goodsSkuId);
- if (inventoryGoodsStock == null) {
- inventoryGoodsStock = createGoodsStock(goodsSkuId);/**
- * 采购入库库存更新命令的工厂
- * @author wangmeng
- *
- */
- @Component
- public class PurchaseInputStockUpdaterFactory<T>
- extends AbstractStockUpdaterFactory<T> {
- /**
- * 构造函数
- * @param stockService 商品库存管理模块的 service 组件
- */
- @Autowired
- public PurchaseInputStockUpdaterFactory(InventoryGoodsStockService stockService) {
- super(stockService);
- }
- /**
- * 获取商品 sku id 集合
- * @return 商品 sku id 集合
- * @throws Exception
- */
- @Override
- protected List<Long> getGoodsSkuIds(T parameter) throws Exception {
- PurchaseInputOrderDTO purchaseInputOrderDTO = (PurchaseInputOrderDTO) parameter;
- List<PurchaseInputOrderItemDTO> purchaseInputOrderItemDTOs =
- purchaseInputOrderDTO.getItems();
- if(purchaseInputOrderItemDTOs == null || purchaseInputOrderItemDTOs.size() == 0) {
- return new ArrayList<>();
- }
- List<Long> goodsSkuIds = new ArrayList<Long>(purchaseInputOrderItemDTOs.size());
- for(PurchaseInputOrderItemDTO purchaseInputOrderItemDTO : purchaseInputOrderItemDTOs) {
- goodsSkuIds.add(purchaseInputOrderItemDTO.getGoodsSkuId());
- }
- return goodsSkuIds;
- }
- /**
- * 创建库存更新命令
- * @param goodsStockDOs 商品库存 DO 对象集合
- * @return 库存更新命令
- * @throws Exception
- */
- @Override
- protected StockUpdater create(List<InventoryGoodsStock> goodsStockDOs, T parameter) throws Exception {
- PurchaseInputOrderDTO purchaseInputOrderDTO = (PurchaseInputOrderDTO) parameter;
- List<PurchaseInputOrderItemDTO> purchaseInputOrderItemDTOs = purchaseInputOrderDTO.getItems();
- Map<Long, PurchaseInputOrderItemDTO> purchaseInputOrderItemDTOMap = new HashMap<>();
- if(purchaseInputOrderItemDTOs != null && purchaseInputOrderItemDTOs.size()> 0) {
- for(PurchaseInputOrderItemDTO purchaseInputOrderItemDTO : purchaseInputOrderItemDTOs) {
- purchaseInputOrderItemDTOMap.put(purchaseInputOrderItemDTO.getGoodsSkuId(),
- purchaseInputOrderItemDTO);
- }
- }
- return new PurchaseInputStockUpdater(goodsStockDOs, stockService, purchaseInputOrderItemDTOMap);
- }
- }
- // 不建议循环中操作 sql, 这里只做演示作用, 实际可以批量操作 sql
- stockService.insert(inventoryGoodsStock);
- }
- goodsStocks.add(inventoryGoodsStock);
- }
- return goodsStocks;
- }
- /**
- * 创建商品库存 DO 对象
- * @param goodsSkuId 商品 sku id
- * @return 商品库存 DO 对象
- */
- private InventoryGoodsStock createGoodsStock(Long goodsSkuId) {
- InventoryGoodsStock goodsStockDO = new InventoryGoodsStock();
- goodsStockDO.setGoodsSkuId(goodsSkuId);
- goodsStockDO.setSaleStockQuantity(0L);
- goodsStockDO.setLockedStockQuantity(0L);
- goodsStockDO.setSaledStockQuantity(0L);
- goodsStockDO.setStockStatus(StockStatus.NOT_IN_STOCK);
- goodsStockDO.setGmtCreate(new Date());
- goodsStockDO.setGmtModified(new Date());
- return goodsStockDO;
- }
- }
采购入库库存更新命令
- /**
- * 采购入库库存更新命令
- * @author zhonghuashishan
- *
- */
- public class PurchaseInputStockUpdater extends AbstractStockUpdater {
- /**
- * 采购入库单条目 DTO 集合
- */
- private Map<Long, PurchaseInputOrderItemDTO> purchaseInputOrderItemDTOMap;
- /**
- * 构造函数
- * @param goodsStockDOs 商品库存 DO 对象
- * @param stockService 商品库存管理模块的 service 组件
- */
- public PurchaseInputStockUpdater(
- List<InventoryGoodsStock> goodsStockDOs,
- InventoryGoodsStockService stockService,
- Map<Long, PurchaseInputOrderItemDTO> purchaseInputOrderItemDTOMap) {
- super(goodsStockDOs, stockService);
- this.purchaseInputOrderItemDTOMap = purchaseInputOrderItemDTOMap;
- }
- /**
- * 更新销售库存
- */
- @Override
- protected void updateSaleStockQuantity() throws Exception {
- for(InventoryGoodsStock goodsStockDO : goodsStockList) {
- PurchaseInputOrderItemDTO purchaseInputOrderItemDTO =
- purchaseInputOrderItemDTOMap.get(goodsStockDO.getGoodsSkuId());
- goodsStockDO.setSaleStockQuantity(goodsStockDO.getSaleStockQuantity()
- + purchaseInputOrderItemDTO.getArrivalCount());
- }
- }
- /**
- * 更新锁定库存
- */
- @Override
- protected void updateLockedStockQuantity() throws Exception {
- }
- /**
- * 更新已销售库存
- */
- @Override
- protected void updateSaledStockQuantity() throws Exception {
- }
- }
实际流转调用代码
- /**
- * <p>
- * 库存中心的商品库存表 服务实现类
- * </p>
- *
- * @author wangmeng
- * @since 2019-12-03
- */
- @Service
- @Slf4j
- public class InventoryGoodsStockServiceImpl extends ServiceImpl<InventoryGoodsStockMapper, InventoryGoodsStock> implements InventoryGoodsStockService {
- /**
- * 采购入库库存更新命令工厂
- */
- @Autowired
- private PurchaseInputStockUpdaterFactory<PurchaseInputOrderDTO> purchaseInputStockUpdateCommandFactory;
- /**
- * 通知库存中心,"采购入库完成" 事件发生了
- * @param purchaseInputOrderDTO 采购入库单 DTO
- * @return 处理结果
- */
- @Override
- public Boolean informPurchaseInputFinished(
- PurchaseInputOrderDTO purchaseInputOrderDTO) {
- try {
- StockUpdater goodsStockUpdateCommand = purchaseInputStockUpdateCommandFactory.create(purchaseInputOrderDTO);
- goodsStockUpdateCommand.updateGoodsStock();
- } catch (Exception e) {
- log.error("error", e);
- return false;
- }
- return true;
- }
- }
申明
本文章首发自本人博客: https://www.cnblogs.com/wang-meng 和公众号: 壹枝花算不算浪漫, 如若转载请标明来源!
感兴趣的小伙伴可关注个人公众号: 壹枝花算不算浪漫
来源: https://www.cnblogs.com/wang-meng/p/11996439.html