前言
之前在我的博客(一枝花算不算浪漫)中已經更新過兩篇設計模式相關的內容
- 【一起學設計模式】策略模式實戰一:基於消息發送的策略模式實戰
- 【一起學習設計模式】策略模式實戰二:配合注解 干掉業務代碼中冗余的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 和公眾號:壹枝花算不算浪漫,如若轉載請標明來源!
感興趣的小伙伴可關注個人公眾號:壹枝花算不算浪漫