DDD~領域事件應用篇(訂單處理變得更清晰)


回到目錄

上一講主要說了領域事件和領域總線,這並不是一個很容易理解的文章,所以本講實例篇主要是為了補充上一講的理論知識,本講實例關注的是實際中的訂單處理模塊,我們知道,訂單處理是電子商務的核心,往往在這里面,會有很多邏輯,在開發時,給我們帶來了不少的難度,如何更好的分離關注點,是本講的主題;本講主要是修改訂單狀態后,為用戶發通知為例,來以此更好的說一下領域事件在實際中的作用。

前言 領域事件使用的設計模式是發布/訂閱模式,或者叫觀察者模式。

一 訂單的幾種狀態,在訂單進入到其中一些狀態時,需要通知用戶

  public enum OrderStatus
    {
        /// <summary>
        /// 表示銷售訂單的已創建狀態 - 表明銷售訂單已被創建(未用)。
        /// </summary>
        [Description("用戶下單")]
        Created = 0,
        /// <summary>
        /// 訂單被用戶取消
        /// </summary>
        [Description("取消訂單")]
        Canceled,
        /// <summary>
        /// 表示銷售訂單的已付款狀態 - 表明客戶已向銷售訂單付款。
        /// </summary>
        [Description("用戶付款")]
        Paid,
        /// <summary>
        /// 表示銷售訂單的已發貨狀態。
        /// </summary>
        [Description("已經發貨")]
        Dispatched,
        /// <summary>
        /// 訂單已經完成
        /// </summary>
        [Description("訂單完成")]
        Finished,

    }

二 為需要通知的狀態,創建領域事件數據源(原來在.net事件里,它一般是EventArgs對象)

    /// <summary>
    /// 訂單已經確認事件源
    /// </summary>
    public class Order_Confirm_Event : Project.Events.EventBase
    {
        public int OrderId { get; set; }
        public string UserName { get; set; }
    }
    /// <summary>
    /// 訂單已經付款事件緣
    /// </summary>
    public class Order_Paid_Event : Project.Events.EventBase
    {
        public int OrderId { get; set; }
        public string UserName { get; set; }
        public decimal TotalPrice { get; set; }
    }
    /// <summary>
    /// 訂單已經發貨事件源
    /// </summary>
    public class Order_Dispatch_Event : Project.Events.EventBase
    {
        public int OrderId { get; set; }
        public string UserName { get; set; }
    }

三 為這些事件源添加事件處理方式

我們一般理解為“行為”,一種事件源可以有多種事件行為,如一個訂單付款事件源,它可以同時有電子郵件行為和短信行為;反之,一個事件處理方式也可以對應多個事件源,如一個電子郵件行為,它可以同時對應訂單付款

和訂單發貨等事件源,所以,領域事件在項目中是非常靈活的。

    /// <summary>
    /// 發Email的事件處理方式
    /// 調用方法:EventBus.Instance.Subscribe<User_Depts_Event>(new SendEmailEventHandler())
    ///      EventBus.Instance.Subscribe<User_Roles_Event>(new SendEmailEventHandler())
    /// </summary>
    public class SendEmail_EventHandler :
       IEventHandler<Order_Confirm_Event>,
        IEventHandler<Order_Dispatch_Event>,
        IEventHandler<Order_Paid_Event>
    {
        static string prefix = "本消息來自電子郵件";

        #region IEventHandler<Order_Confirm_Event> 成員

        public void Handle(Order_Confirm_Event evt)
        {
            Logger.Core.LoggerFactory.Instance.Logger_Info(string.Format("尊敬的客戶{0},你的訂單已經確認,訂單號{1},請盡快付款!({2})[{3}]"
                , evt.UserName
                , evt.OrderId
                , evt.EventDate
                , prefix));
        }

        #endregion

        #region IEventHandler<Order_Dispatch_Event> 成員

        public void Handle(Order_Dispatch_Event evt)
        {
            Logger.Core.LoggerFactory.Instance.Logger_Info(string.Format("尊敬的客戶{0},你的訂單已經發貨,訂單號{1},請注意查收!({2})[{3}]"
                , evt.UserName
                , evt.OrderId
                , evt.EventDate
                , prefix));

        }

        #endregion

        #region IEventHandler<Order_Paid_Event> 成員

        public void Handle(Order_Paid_Event evt)
        {
            Logger.Core.LoggerFactory.Instance.Logger_Info(string.Format("尊敬的客戶{0},你的訂單已經成功付款,訂單號{1},付款金額為{2}元,我們會盡快安排發貨!({3})[{4}]"
                 , evt.UserName
                 , evt.OrderId
                 , evt.TotalPrice
                 , evt.EventDate
                 , prefix));
        }

        #endregion
    }
    /// <summary>
    /// 發短信的事件處理方式
    /// </summary>
    public class SendSMS_EventHandler :
         IEventHandler<Order_Confirm_Event>,
         IEventHandler<Order_Dispatch_Event>,
         IEventHandler<Order_Paid_Event>
    {
        static string prefix = "本消息來自短信";

        #region IEventHandler<Order_Confirm_Event> 成員

        public void Handle(Order_Confirm_Event evt)
        {
            Logger.Core.LoggerFactory.Instance.Logger_Info(string.Format("尊敬的客戶{0},你的訂單已經確認,訂單號{1},請盡快付款!({2})[{3}]"
                , evt.UserName
                , evt.OrderId
                , evt.EventDate
                , prefix));
        }

        #endregion

        #region IEventHandler<Order_Dispatch_Event> 成員

        public void Handle(Order_Dispatch_Event evt)
        {
            Logger.Core.LoggerFactory.Instance.Logger_Info(string.Format("尊敬的客戶{0},你的訂單已經發貨,訂單號{1},請注意查收!({2})[{3}]"
                , evt.UserName
                , evt.OrderId
                , evt.EventDate
                , prefix));

        }

        #endregion

        #region IEventHandler<Order_Paid_Event> 成員

        public void Handle(Order_Paid_Event evt)
        {
            Logger.Core.LoggerFactory.Instance.Logger_Info(string.Format("尊敬的客戶{0},你的訂單已經成功付款,訂單號{1},付款金額為{2}元,我們會盡快安排發貨!({3})[{4}]"
                 , evt.UserName
                 , evt.OrderId
                 , evt.TotalPrice
                 , evt.EventDate
                 , prefix));
        }

        #endregion
    }

四 訂閱領域事件

我們需要有一個入口來訂閱領域事件,如訂閱訂單確認事件,訂單付款事件等,簡單的做法是在global里統一注冊,而標准合理的作法,我覺得應該在訂單controller的靜態構造方法里去注冊它,因為只有用戶操作訂單相關模塊時,才可能觸

發訂單這些事件!

     /// <summary>
        /// 類的構造方法,處理與具體實例無法的東西
        /// </summary>
        static OrderController()
        {
            #region 訂閱相關領域事件

            #region 訂閱發email處理方式
            EventBus.Instance.Subscribe<Order_Confirm_Event>(new SendEmail_EventHandler());
            EventBus.Instance.Subscribe<Order_Dispatch_Event>(new SendEmail_EventHandler());
            EventBus.Instance.Subscribe<Order_Paid_Event>(new SendEmail_EventHandler());
            #endregion

            #region 訂閱發短信的處理方式
            EventBus.Instance.Subscribe<Order_Confirm_Event>(new SendSMS_EventHandler());
            EventBus.Instance.Subscribe<Order_Dispatch_Event>(new SendSMS_EventHandler());
            EventBus.Instance.Subscribe<Order_Paid_Event>(new SendSMS_EventHandler());
            #endregion

            #endregion
        }

我們看到了,每種訂單事件源都被注冊了電子郵件和短信兩種事件處理方式,這在對應的事件被觸發(發布,publish)之后,它們會被執行。

六 觸發具體事件

具體的事件在具體的方法里,獨立的去觸發,一般它會在業務邏輯層完成

     /// <summary>
        /// 用戶下單:create
        /// </summary>
        /// <param name="entity"></param>
        public void DoOrder(Order_Info entity)
        {
            entity.OrderStatus = (int)OrderStatus.Created;
            _orderRepository.Insert(entity);
            entity.Order_Detail.ToList().ForEach(j => j.OrderId = entity.Id);
            _orderDetailRepository.Insert(entity.Order_Detail);
            EventBus.Instance.Publish(new Order_Confirm_Event { OrderId = entity.Id, UserName = entity.UserName });
        }

        /// <summary>
        /// 訂單付款:paid
        /// </summary>
        /// <param name="entity"></param>
        public void PaidOrder(Order_Info entity)
        {
            entity.OrderStatus = (int)OrderStatus.Paid;
            _orderRepository.Update(entity);
            EventBus.Instance.Publish(new Order_Paid_Event { OrderId = entity.Id, TotalPrice = entity.TotalPrice, UserName = entity.UserName });
        }

        /// <summary>
        /// 訂單發貨:dispatch
        /// </summary>
        /// <param name="entity"></param>
        public void DispatchOrder(Order_Info entity)
        {
            entity.OrderStatus = (int)OrderStatus.Dispatched;
            _orderRepository.Update(entity);
            EventBus.Instance.Publish(new Order_Dispatch_Event { OrderId = entity.Id, UserName = entity.UserName });
        }

八 最后,我們看一下處理處理頁面和結果的截圖

生成的日志

生成的日志內容,類似於用戶上到的電子郵件或者短信的內容

怎么樣,看完這個例子相信您對領域事件有了更清晰的認識了吧,呵呵!

回到目錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM