【一起學設計模式】狀態模式+裝飾器模式+簡單工廠模式實戰:(一)提交個訂單我到底經歷了什麼鬼?
前言
之前在我的部落格(一枝花算不算浪漫)中已經更新過兩篇設計模式相關的內容
- 【一起學設計模式】策略模式實戰一:基於訊息傳送的策略模式實戰
- 【一起學習設計模式】策略模式實戰二:配合註解 幹掉業務程式碼中冗餘的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 和公眾號:壹枝花算不算浪漫,如若轉載請標明來源!
感興趣的小夥伴可關注個人公眾號:壹枝花算不算浪漫
相關推薦
【一起學設計模式】狀態模式+裝飾器模式+簡單工廠模式實戰:(一)提交個訂單我到底經歷了什麼鬼?
前言 之前在我的部落格(一枝花算不算浪漫)中已經更新過兩篇設計模式相關的內容 【一起學設計模式】策略模式實戰一:基於訊息傳送的策略模式實戰 【一起學習設計模式】策略模式實戰二:配合註解 幹掉業務程式碼中冗餘的if else... 【一起學設計模式】訪問者模式實戰:許可權管理樹刪節點操作 【一起學設計模式】命
【一起學設計模式】中介者模式+觀察者模式+備忘錄模式實戰:(二)提交個訂單我到底經歷了什麼鬼?
前言 再多的話就不說了,這個是接著上一講: 【一起學設計模式】狀態模式+裝飾器模式+簡單工廠模式實戰:(一)提交個訂單我到底經歷了什麼鬼? 一起的,一些多餘的贅述請先看這個篇文章。 業務場景 一圖流,還是上一篇文章中一樣的圖,接下來我們就梳理下總結模式、觀察者模式、備忘錄模式的應用: 訂單中心: 1、訂單
【一起學設計模式】命令模式+模板方法+工廠方法實戰: 如何優雅的更新商品庫存...
前言 之前在我的部落格(一枝花算不算浪漫)中已經更新過兩篇設計模式相關的內容 【一起學設計模式】策略模式實戰一:基於訊息傳送的策略模式實戰 【一起學習設計模式】策略模式實戰二:配合註解 幹掉業務程式碼中冗餘的if else... 【一起學設計模式】訪問者模式實戰:許可權管理樹刪除節點操作 上面內容都是基於
【一起學設計模式】觀察者模式實戰:真實專案中屢試不爽的瓜娃EventBus到底如何實現觀察者模式的?
申明 本文章首發自本人公眾號:壹枝花算不算浪漫,如若轉載請標明來源! 感興趣的小夥伴可關注個人公眾號:壹枝花算不算浪漫 22.jpg 前言 之前出過一個設計模式的系列文章,這些文章和其他講設計模式的文章 有些不同 文章沒有拘泥於講解設計模式的原理,更多的是梳理工作中實際用到的一些設計模式,並提取出對應業務模
從原理層面掌握HandlerMethod、InvocableHandlerMethod、ServletInvocableHandlerMethod的使用【一起學Spring MVC】
每篇一句 想當火影的人沒有近道可尋,當上火影的人同樣無路可退 前言 HandlerMethod它作為Spring MVC的非公開API,可能絕大多數小夥伴都對它比較陌生,但我相信你對它又不是那麼的生疏,因為你可能沒用過但肯定見過。 比如Spring MVC的攔截器HandlerInterceptor的攔截
從原理層面掌握@SessionAttribute的使用【一起學Spring MVC】
每篇一句 不是你當上了火影大家就認可你,而是大家都認可你才能當上火影 前言 該註解顧名思義,作用是將Model中的屬性同步到session會話當中,方便在下一次請求中使用(比如重定向場景~)。 雖然說Session的概念在當下前後端完全分離的場景中已經變得越來越弱化了,但是若為web開發者來說,我仍舊強烈
從原理層面掌握@RequestAttribute、@SessionAttribute的使用【一起學Spring MVC】
每篇一句 改我們就改得:取其精華,去其糟粕。否則木有意義 前言 如果說知道@SessionAttributes這個註解的人已經很少了,那麼不需要統計我就可以確定的說:知道@RequestAttribute註解的更是少之又少。我覺得主要有如下兩個原因: @RequestAttribute這個註解很新,Sp
從原理層面掌握@ModelAttribute的使用(使用篇)【一起學Spring MVC】
每篇一句 每個人都應該想清楚這個問題:你是祖師爺賞飯吃的,還是靠老天爺賞飯吃的 前言 上篇文章 描繪了@ModelAttribute的核心原理,這篇聚焦在場景使用上,演示@ModelAttribute在不同場景下的使用,以及注意事項(當然有些關聯的原理也會涉及)。 為了進行Demo演示,首先得再次明確一下
從原理層面掌握@ModelAttribute的使用(核心原理篇)【一起學Spring MVC】
每篇一句 我們應該做一個:胸中有藍圖,腳底有計劃的人 前言 Spring MVC提供的基於註釋的程式設計模型,極大的簡化了web應用的開發,我們都是受益者。比如我們在@RestController標註的Controller控制器元件上用@RequestMapping、@ExceptionHandler等註
Android [Camera 原始碼] 3A 模式和狀態轉換(3A Modes and State) Google官方文件(五)
Google原始碼網地址連結:https://source.android.com/devices/camera 該Google Camera的文件為系列文章,文章列表: overview Camera3 HAL Subsystem Metadata and Con
設計模式:(一)簡單工廠
問題:寫一個計算器的控制檯應用程式 功能要求: (1)實現+、-、*、/四種基本運算; (2)程式執行時,使用者輸入兩個數和運算子號,即可得到運算結果。 public class Operation //運算基類 { private double _numb
基本設計模式學習筆記:(一)常見的七種面向物件設計原則
0.概述 面向物件設計原則為支援可維護性複用而誕生,這些原則蘊含在很多設計模式中,他們是從許多設計方案中總結出來的指導性原則1.單一原則 一個類只負責一個功能領域中的相應職責,或者說:就一個類而言,應該只有一個引起它變化的原因。個人總結:將不同職責的方法放在
【10分鐘學Spring】:(一)初識Spring框架
簡介 Spring是一個輕量級的企業級的Java開發框架。主要是用來替代原來更加重量級的企業級Java技術,比如EJB(Enterprise JavaBean)、Java資料物件(Java Data Object)等。Spring的出現極大簡化了Java開發。 另外Spring框架是一個一體化的框架,它不僅能
【原創】源碼角度分析Android的消息機制系列(一)——Android消息機制概述
run 權限 開發 等待 通過 讀取 概述 走了 color ι 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 1.為什麽需要Android的消息機制 因為Android系統不允許在子線程中去訪問UI,即Android系統不允許在子線程中更新UI。 為什麽不允許
【微服務從入門到精通】:(一)微服務的藍綠發布及灰度發布
采樣 前端 入門 後端 blog 文件 風險 性能 切換 藍綠部署 基本上,藍綠部署是一種以可預測的方式發布應用的技術,目的是減少發布過程中服務停止的時間。 簡單來說,你需要準備兩個相同的環境(基礎架構),在藍色環境運行當前生產環境中的應用,也就是舊版本應用,如圖中 A
【轉載】恢復誤刪文件--DOS命令應用實例(一)
就是 開始 miss 幫助 屬於 三種 txt文件 意思 ron 《電腦愛好者》報轉載第一輯第二篇之恢復誤刪文件--DOS命令應用實例(一)
【MPC5744P】S32DS中Processor Expert自動生成程式碼工具使用教程(一) 開發環境搭建
MPC5744P是NXP近幾年推出來的主打安全功能的雙核MCU,非常適合在汽車控制器相關產品中使用,非常強大。但是強大的同時,也意味著開發難度增大。 MPC5744P外設功能相關的暫存器非常之多,且對應的參考教程非常少,像STM32之類的工業MCU開發難度根本無法與之相比,早期只能依據官方參
【更新】Essential Studio for ASP.NET MVC更新至2018 v4(一)
下載Essential Studio for ASP.NET MVC最新版本 Essential Studio for ASP.NET MVC控制元件包是一款MVC介面開發包,它包含了幾乎所有企業級Web應用程式開發所需要的控制元件,如Grids、 Charts、Gauges、Menus、Calenda
【專案管理和構建】十分鐘教程,eclipse配置maven + 建立maven專案(三)
上篇博文中我們介紹了maven下載、安裝和配置(二),這篇博文我們配置一下eclipse,將它和maven結合,並我們建立一個maven的專案。 準備工作 在eclipse配置maven之前需要我們做好準備工作,如下: 1. 安裝jdk 2. 已安裝好 maven,將maven配置成功 3. 下載
【機器學習實戰系列】讀書筆記之AdaBoost演算法公式推導和例子講解(一)
最近在看整合演算法AdaBoost,推薦先看李航的統計學習方法第8章,然後再看機器學習實戰第7章,李航的書上的公式推導講的很詳細了,但是很多地方對於初學者來說,還是需要時間去理解和消化的。本文將從以下幾個方面來介紹AdaBoost演算法。一、AdaBoost演算法公式推導二、