如何开始DDD(完) - young.han - 博客园
Excerpt
连续写了两篇文章,这一篇我想是序的完结篇了。结合用户注册的例子再将他简单丰富一下。在这里只添加一个简单需求,就是用户注册成功后给用户发一封邮件。补充一下之前的代码 上面的代码是存在一点问题的,了解DDD的人都知道,此时user并没有持久化或者持久化是否成功是不确定的,假设此时持久化user失败了,但
连续写了两篇文章,这一篇我想是序的完结篇了。结合用户注册的例子再将他简单丰富一下。在这里只添加一个简单需求,就是用户注册成功后给用户发一封邮件。补充一下之前的代码
1 2 3 4 5 6 7 8 9 10 11 12
| <span>public</span> <span>class</span><span> DomainService { </span><span>public</span> <span>void</span><span> Register(User user) { </span><span>if</span><span> (_userRepository.IsLoginIdExist(user.LoginId)) { </span><span>throw</span> <span>new</span> Exception(<span>"</span><span>用户名已存在</span><span>"</span><span>); }
_userRepository.Add(user); MailService.Send(user.Email, </span><span>"</span><span>邮件内容</span><span>"</span><span>); } }</span>
|
上面的代码是存在一点问题的,了解DDD的人都知道,此时user并没有持久化或者持久化是否成功是不确定的,假设此时持久化user失败了,但邮件却发送出去了,这显然不是我们想要的结果。怎么办?我能想到的是两种办法。
第一种:创建一个发送邮件的model。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <span>public</span> <span>class</span><span> MailMessage { </span><span>public</span> MailMessage(<span>string</span> receiver, <span>string</span><span> content) { </span><span>this</span>.Receiver =<span> receiver; </span><span>this</span>.Content =<span> content; }
</span><span>public</span> <span>string</span> Receiver { <span>get</span>; <span>private</span> <span>set</span><span>; } </span><span>public</span> <span>string</span> Content { <span>get</span>; <span>private</span> <span>set</span><span>; } }
</span><span>public</span> <span>class</span><span> DomainService { </span><span>public</span> <span>void</span><span> Register(User user) { </span><span>if</span><span> (_userRepository.IsLoginIdExist(user.LoginId)) { </span><span>throw</span> <span>new</span> Exception(<span>"</span><span>用户名已存在</span><span>"</span><span>); }
_userRepository.Add(user); _mailRepository.Add(</span><span>new</span> MailMessage(user.Email, <span>"</span><span>邮件内容</span><span>"</span><span>)); } }</span>
|
在添加用户的时候同时添加一条邮件消息,这样他们将会在同一个事务中,要么一起成功,要么一起失败。最后再设计个计划任务,从邮件记录表中取出记录依次发送邮件,发送成功的可以标记一下,至于怎么做就不细讲了。
第二种:就是这一篇我要介绍的使用事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| <span>public</span> <span>class</span><span> UserRegistered : IEvent { </span><span>public</span> UserRegistered(<span>string</span> name, <span>string</span><span> email) { </span><span>this</span>.Name =<span> name; </span><span>this</span>.Email =<span> email; }
</span><span>public</span> <span>string</span> Name { <span>get</span>; <span>private</span> <span>set</span><span>; } </span><span>public</span> <span>string</span> Email { <span>get</span>; <span>private</span> <span>set</span><span>; } }
</span><span>public</span> <span>class</span> UserRegisteredHandler : IEventHandler<UserRegistered><span> { </span><span>public</span> <span>void</span><span> Handle(UserRegistered @event) { </span><span>//</span><span>TODO.. 发送邮件 </span> <span> } }
</span><span>public</span> <span>class</span><span> User : IEventPublisher { </span><span>private</span> <span>readonly</span> IList<IEvent> _uncommittedEvents = <span>new</span> List<IEvent><span>(); IEnumerable</span><IEvent><span> IEventPublisher.Events { </span><span>get</span> { <span>return</span> <span>this</span><span>._uncommittedEvents; } }
</span><span>public</span> User(<span>string</span> name, <span>string</span> password, <span>string</span><span> email) { </span><span>this</span>.Name =<span> name; </span><span>this</span>.Password =<span> password; </span><span>this</span>.Email =<span> email;
_uncommittedEvents.Add(</span><span>new</span><span> UserRegistered(name, email)); }
</span><span>public</span> <span>string</span> Name { <span>get</span>; <span>private</span> <span>set</span><span>; } </span><span>public</span> <span>string</span> Password { <span>get</span>; <span>private</span> <span>set</span><span>; } </span><span>public</span> <span>string</span> Email { <span>get</span>; <span>private</span> <span>set</span><span>; } }</span>
|
这样用户注册会产生一个事件。持久化成功后,会将事件发布出去,这样EventBus就会监听并处理此事件。上面的代码可能阅读理解起来不是那么的直白,具体的实现起来也并非就这么简单,只是提出一种方法。具体实现我的开源代码里也有相关例子https://github.com/imyounghan/thinknet[
](http://thinknet.codeplex.com/)
总结
以上三篇文章我也主要是从写代码的角度去介绍如何DDD,强调一下我不是在教你如何写代码,只是为了展示用DDD如何实现,领域里的模型更应该能表达业务,他的价值更并不仅于此。而且以上的描述不一定完全正确,也不是告诉你一定要如何做,这也需要你自己的思考,如果有不对的地方欢迎你的指正,毕竟DDD我在学习过程中,也能从中受益。
如果我们过多的精力花在如何写代码上,可能是收集的工具类库还不强大,或者是还没有一个能够方便快捷开发的框架,当然一个好的框架带来的好处会很多。一个框架终究是有办法和技术能力去实现完成的,但是如何分析和理解业务,然后从中挖掘出便于阅读和表达业务的模型确定一件不容易的事情,他并不是通过某种技术办法就能实现的。所以我个人觉得设计模型,划分界限上下文是需要不断的积累领域业务知识才能做到的。
“领域驱动设计”和“实现领域驱动”这两本书应该是最经典的了,知识点也很多,阅读此书你会得到更多的收获!