以前在個人博客(一枝花算不算浪漫)中已經更新過兩篇設計模式相關的內容html
上面內容都是基於真實業務場景精簡後的設計(工做中真實場景使用到的)。java
以前爲了學習設計模式,看過網上不少相關博客講解,大都是畫下UML類圖,舉例幾個絕不相干的demo,看了幾遍仍然是雲裏霧裏。sql
學習設計模式只有在真正的業務場景去使用纔會更好的理解其精髓。這裏舉例本身工做中電商的業務場景,而後配合一些業務功能的實現,來學會設計模式,使本身的代碼更優雅。設計模式
在一個電商或者進銷存業務中,咱們都有庫存的概念。
更新庫存又分爲不少種場景:購買、退貨、下單、取消訂單、加購物車等等app
固然,咱們以前也見過策略模式,這種業務能夠抽象爲每一個策略去作。可是這裏咱們使用新的設計模式來嘗試完成它。ide
命令模式command
設置一系列的command命令,咱們將不一樣類型的庫存更新邏輯,封裝了不一樣的庫存更新命令。函數
命令模式還有一個很經典的場景,就是作這個命令撤銷。若是咱們在執行這個命令的過程當中,發現命令中的某個步驟失敗了,咱們能夠在command裏面實現一套cancel的邏輯,撤銷這個命令以前作的全部操做,對已經完成的好作執行反步驟。學習
模板方法模式
將一些通用的步驟抽取到抽象基類,另一個基於模板的模式限定了每一個庫存更新的過程都是同樣的,按照同樣的步驟和順序走,很清晰。後面若是要修改更新庫存的邏輯,或者hi新增一種庫存更新的邏輯,都是按照同樣的步驟和順序去走。this
工廠方法模式
工廠方法模式,就是將工廠模式和模板方法模式,結合起來。
就是說,可能咱們須要的不是一個工廠,不一樣的工廠建立不一樣的產品,可是這些工廠之間有一些通用的邏輯,能夠抽取到父工廠裏面去,子工廠就專一於本身的事情就能夠了。設計
/** * 商品庫存更新命令的接口 * * @author wangmeng * @blog https://www.cnblogs.com/wang-meng/ * @create 2019-12-05 06:42 **/ public interface StockUpdater { /** * 更新商品庫存 * @return 處理結果 */ Boolean updateGoodsStock(); }
/** * 庫存更新命令工廠接口 * * @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); } } }
/** * @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 和公衆號:壹枝花算不算浪漫,如若轉載請標明來源!
感興趣的小夥伴可關注我的公衆號:壹枝花算不算浪漫