回到目錄 閑話多說 領域事件大叔感覺是最不好講的一篇文章,所以拖欠了很久,但最終還是在2015年年前(陰曆)把這個知識點講一下,事件這個東西早在C#1.0時代就有了,那時學起來也是一個費勁,什麼是委托,哪個是事件,搞的大家是糊裡糊塗,進入C#2.0時代後,大叔也買了一本書,對於delegate和ev
閑話多說
領域事件大叔感覺是最不好講的一篇文章,所以拖欠了很久,但最終還是在2015年年前(陰曆)把這個知識點講一下,事件這個東西早在C#1.0時代就有了,那時學起來也是一個費勁,什麼是委托,哪個是事件,搞的大家是糊裡糊塗,進入C#2.0時代後,大叔也買了一本書,對於delegate和event這兩個知識點看了至少有20幾遍,感覺稍微有點明白了,明白了其中的真諦和用意。
委托:方法的規範,方法的模板,可以代表一類方法的集合
事件:委托的實例,事件在使用之前需要為它賦值,當然賦的就是一個方法;事件可以註冊和取消,當你註冊一個事件之後,在事件被觸發後,被註冊的方法將會被執行,這一般被稱為“方法的回調”,在設計模式里,又被稱為“pub/sub模式”,即發佈/訂閱模式;在C#語言發展過程中,設計得為程式開發者考慮的很多,有些寫法得到了精簡,如Action和Func委托的出現之後,我們基本上告別了delegate,這對程式開發人員無疑是一件好事。
大叔框架中的事件
在大叔框架里,事件是常客,比如在早期的倉儲代碼里,你可以傳遞一個Action<string>的委托,來進行日誌的記錄,這種方法在IoC出現後,被大叔屏蔽了,原因不在這裡說了,還有就是在N層架構里,WEB層與BLL層進行通訊時,WEB層通過HttpClient請求第三方的API獲取數據,而BLL層的方法需要用到這個第三方API的返回值,而在BLL層直接訪問HTTP顯然是不合適的,所以,在WEB層到BLL層的方法參數設計時,需要有一個委托來接改從WEB層回調的方法返回值,這種代碼一般稱為“方法回調”。
web層向BLL層傳入一個委托
var entity = rechargeService.RechargeAuto( task, beforeTime, out result, (studentid, money) => { //代碼 });
BLL層接改這個委托的返回值,代碼在調用bll層這個方法時,首先會回調web層的http的方法
public Task_xuexiba_Recharge RechargeAuto( Task_Info task, DateTime beforeTime, out bool result, Func<int, decimal, RechargeXuexibaDTO> api) { //代碼 }
var apiEntity = api(task.Task_ParametersForXuexibaRecharge.StudentID, task.Task_ParametersForXuexibaRecharge.Money);
Lind.DDD框架里的領域事件
事件源尾碼:Event
事件處理方法尾碼:EventHandler
領域事件一般出現個領域實體里,在實體被建立時,會訂閱和自己有關的事件,每個事件都有一個或者多個事件處理方法,事件處理方法可以進行資料庫操作,或者網路和文件的操作,如發通知,寫文件等,所以有時候我們的事件需要設計成非同步的事件。
程式中的事件事件
#region 領域模型 public class Order { public Order() { Lind.DDD.Events.EventBus.Instance.Subscribe(new OrderInsertEventHandler()); Lind.DDD.Events.EventBus.Instance.Subscribe<OrderPaid>(new OrderUpdateEventHandler()); } public System.Guid Id { get; set; } public System.Guid UserId { get; set; } public string UserName { get; set; } public decimal TotalFee { get; set; } /// <summary> /// 用戶提交並確認訂單 /// </summary> public void ComfirmOrder() { //事件發佈 Lind.DDD.Events.EventBus.Instance.Publish(new OrderConfirm { TotalFee = TotalFee, UserName = UserName, UserId = UserId, }); } } #endregion
下麵是領域事件源
/// <summary> /// 訂單被確認的事件源 /// </summary> public class OrderConfirm : Lind.DDD.Events.IEvent { public override string ToString() { return "訂單已經確認"; } /// <summary> /// 訂單總金額 /// </summary> public decimal TotalFee { get; set; } /// <summary> /// 購買者ID /// </summary> public Guid UserId { get; set; } /// <summary> /// 購買者 /// </summary> public string UserName { get; set; } #region IEvent 成員 public Guid AggregateRoot { get { throw new NotImplementedException(); } } #endregion }
下麵是領域事件的處理程式
/// <summary> /// 訂單被插入時的處理程式 /// </summary> public class OrderInsertEventHandler : Lind.DDD.Events.IEventHandler<Events.OrderConfirm> { #region IEventHandler<OrderSigned> 成員 public void Handle(Events.OrderConfirm evt) { //處理訂單確認的邏輯 var orderRepository = new Lind.DDD.Repositories.EF.EFRepository<Orders>(); orderRepository.SetDataContext(new testEntities()); orderRepository.Insert(new Orders { Id = Guid.NewGuid(), OrderStatus = 1, TotalFee = evt.TotalFee, UserId = evt.UserId, UserName = evt.UserName, }); } #endregion }
如果希望將自己的事件處理程式設計成異常的,即不阻塞當前線程的,可以讓它添加HandlesAsynchronouslyAttribute這個特性,如下麵這個發送Email的處理程式就是一個非同步的。
/// <summary> /// 發郵件功能[某個事件的行為] /// </summary> [HandlesAsynchronouslyAttribute] public class SendEmailEventHandler : IEventHandler<OrderEvent>, IEventHandler<UserEvent> { #region IEventHandler<OrderEvent> 成員 public void Handle(OrderEvent evt) { Console.WriteLine("生成和確認訂單{0}時發Email", evt.OrderId); } #endregion #region IEventHandler<UserEvent> 成員 public void Handle(UserEvent evt) { Console.WriteLine("建立用戶後發Email,用戶ID{0}", evt.UserId); } #endregion }
感謝各位的閱讀!