連續寫了兩篇文章,這一篇我想是序的完結篇了。結合用戶注冊的例子再將他簡單豐富一下。在這里只添加一個簡單需求,就是用戶注冊成功后給用戶發一封郵件。補充一下之前的代碼
public class DomainService { public void Register(User user) { if (_userRepository.IsLoginIdExist(user.LoginId)) { throw new Exception("用戶名已存在"); } _userRepository.Add(user); MailService.Send(user.Email, "郵件內容"); } }
上面的代碼是存在一點問題的,了解DDD的人都知道,此時user並沒有持久化或者持久化是否成功是不確定的,假設此時持久化user失敗了,但郵件卻發送出去了,這顯然不是我們想要的結果。怎么辦?我能想到的是兩種辦法。
第一種:創建一個發送郵件的model。
public class MailMessage { public MailMessage(string receiver, string content) { this.Receiver = receiver; this.Content = content; } public string Receiver { get; private set; } public string Content { get; private set; } } public class DomainService { public void Register(User user) { if (_userRepository.IsLoginIdExist(user.LoginId)) { throw new Exception("用戶名已存在"); } _userRepository.Add(user); _mailRepository.Add(new MailMessage(user.Email, "郵件內容")); } }
在添加用戶的時候同時添加一條郵件消息,這樣他們將會在同一個事務中,要么一起成功,要么一起失敗。最后再設計個計划任務,從郵件記錄表中取出記錄依次發送郵件,發送成功的可以標記一下,至於怎么做就不細講了。
第二種:就是這一篇我要介紹的使用事件。
public class UserRegistered : IEvent { public UserRegistered(string name, string email) { this.Name = name; this.Email = email; } public string Name { get; private set; } public string Email { get; private set; } } public class UserRegisteredHandler : IEventHandler<UserRegistered> { public void Handle(UserRegistered @event) { //TODO.. 發送郵件 } } public class User : IEventPublisher { private readonly IList<IEvent> _uncommittedEvents = new List<IEvent>(); IEnumerable<IEvent> IEventPublisher.Events { get { return this._uncommittedEvents; } } public User(string name, string password, string email) { this.Name = name; this.Password = password; this.Email = email; _uncommittedEvents.Add(new UserRegistered(name, email)); } public string Name { get; private set; } public string Password { get; private set; } public string Email { get; private set; } }
這樣用戶注冊會產生一個事件。持久化成功后,會將事件發布出去,這樣EventBus就會監聽並處理此事件。上面的代碼可能閱讀理解起來不是那么的直白,具體的實現起來也並非就這么簡單,只是提出一種方法。具體實現我的開源代碼里也有相關例子https://github.com/imyounghan/thinknet
總結
以上三篇文章我也主要是從寫代碼的角度去介紹如何DDD,強調一下我不是在教你如何寫代碼,只是為了展示用DDD如何實現,領域里的模型更應該能表達業務,他的價值更並不僅於此。而且以上的描述不一定完全正確,也不是告訴你一定要如何做,這也需要你自己的思考,如果有不對的地方歡迎你的指正,畢竟DDD我在學習過程中,也能從中受益。
如果我們過多的精力花在如何寫代碼上,可能是收集的工具類庫還不強大,或者是還沒有一個能夠方便快捷開發的框架,當然一個好的框架帶來的好處會很多。一個框架終究是有辦法和技術能力去實現完成的,但是如何分析和理解業務,然后從中挖掘出便於閱讀和表達業務的模型確定一件不容易的事情,他並不是通過某種技術辦法就能實現的。所以我個人覺得設計模型,划分界限上下文是需要不斷的積累領域業務知識才能做到的。
“領域驅動設計”和“實現領域驅動”這兩本書應該是最經典的了,知識點也很多,閱讀此書你會得到更多的收獲!