回到目錄
上一講主要說了領域事件和領域總線,這并不是一個很容易了解的文章,是以本講執行個體篇主要是為了補充上一講的理論知識,本講執行個體關注的是實際中的訂單處理子產品,我們知道,訂單處理是電子商務的核心,往往在這裡面,會有很多邏輯,在開發時,給我們帶來了不少的難度,如何更好的分離關注點,是本講的主題;本講主要是修改訂單狀态後,為使用者發通知為例,來以此更好的說一下領域事件在實際中的作用。
前言 領域事件使用的設計模式是釋出/訂閱模式,或者叫觀察者模式。
一 訂單的幾種狀态,在訂單進入到其中一些狀态時,需要通知使用者
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 });
}
八 最後,我們看一下處理處理頁面和結果的截圖
生成的日志
生成的日志内容,類似于使用者上到的電子郵件或者短信的内容
怎麼樣,看完這個例子相信您對領域事件有了更清晰的認識了吧,呵呵!
作者:倉儲大叔,張占嶺,
榮譽:微軟MVP
QQ:853066980
支付寶掃一掃,為大叔打賞!
