1. 程式人生 > >【一起學設計模式】狀態模式+裝飾器模式+簡單工廠模式實戰:(一)提交個訂單我到底經歷了什麼鬼?

【一起學設計模式】狀態模式+裝飾器模式+簡單工廠模式實戰:(一)提交個訂單我到底經歷了什麼鬼?

前言

之前在我的部落格(一枝花算不算浪漫)中已經更新過兩篇設計模式相關的內容

  • 【一起學設計模式】策略模式實戰一:基於訊息傳送的策略模式實戰
  • 【一起學習設計模式】策略模式實戰二:配合註解 幹掉業務程式碼中冗餘的if else...
  • 【一起學設計模式】訪問者模式實戰:許可權管理樹刪節點操作
  • 【一起學設計模式】命令模式+模板方法+工廠方法實戰: 如何優雅的更新商品庫存...

上面內容都是基於真實業務場景精簡後的設計(工作中真實場景使用到的)。

之前為了學習設計模式,看過網上很多相關部落格講解,大都是畫下UML類圖,舉例幾個毫不相干的demo,看了幾遍仍然是雲裡霧裡。

因為自己現在做的專案就是屬於B2C的商城,專案中使用到了大量的設計模式,所以這裡精簡真實的業務場景,將核心的業務程式碼抽離出來。程式碼不涉及任何公司資訊,所有敏感資訊都已遮蔽,程式碼只用作學習交流使用。

業務場景

一圖流,首先看下提交訂單 我們抽象出的一些場景:

訂單中心:
1、訂單中心建立訂單
2、訂單狀態流轉(狀態模式)
3、記錄操作日誌(裝飾器模式+簡單工廠模式)
4、訂單中心通知 庫存中心更新庫存

排程中心:
1、庫存中心更新本地庫存(使用命令模式+模板方法模式+工廠模式)
這個上講已經說過:【一起學設計模式】命令模式+模板方法+工廠方法實戰: 如何優雅的更新商品庫存...
2、將更新庫存資料放到訊息中,排程中心消費訊息(中介模式)
3、放入訊息佇列中,判斷佇列是否放滿了,如果放滿了需要建立離線儲存(備忘錄模式)
4、非同步監聽訊息處理結果(觀察者模式)

這個模型應該很簡單,我們來一步步拆解 一步步程式碼分析

訂單狀態流轉 + 操作日誌記錄

程式碼實現

  1. 訂單中心提交訂單操作

    /**
    * 訂單狀態管理器
    */
    @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;
    }
  2. 訂單狀態管理器

    /**
     * 會自動記錄日誌的訂單狀態管理器
     * @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)); 
        }
    }
  3. 日誌操作工廠

    /**
     * 訂單操作內容工廠
     * @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;
        }
    
    }
  4. 訂單狀態流轉
    我們只列出來訂單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;
    
        // 這裡還會有更多的訂單狀態:支付、確認收貨、發貨、退貨等等狀態流轉
    }
  5. 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命令應用實例(一)

MPC5744PS32DS中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演算法公式推導二、