如何开始DDD(完)
连续写了两篇文章,这一篇我想是序的完结篇了。结合用户注册的例子再将他简单丰富一下。在这里只添加一个简单需求,就是用户注册成功后给用户发一封邮件。补充一下之前的代码
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我在学习过程中,也能从中受益。
如果我们过多的精力花在如何写代码上,可能是收集的工具类库还不强大,或者是还没有一个能够方便快捷开发的框架,当然一个好的框架带来的好处会很多。一个框架终究是有办法和技术能力去实现完成的,但是如何分析和理解业务,然后从中挖掘出便于阅读和表达业务的模型确定一件不容易的事情,他并不是通过某种技术办法就能实现的。所以我个人觉得设计模型,划分界限上下文是需要不断的积累领域业务知识才能做到的。
“领域驱动设计”和“实现领域驱动”这两本书应该是最经典的了,知识点也很多,阅读此书你会得到更多的收获!
如何开始DDD(完)的更多相关文章
- 用CQRS+ES实现DDD
用CQRS+ES实现DDD 这篇文章应该算是对前三篇的一个补充,在写之前说个题外话,有园友评论这是在用三层架构在写DDD,我的个人理解DDD是一种设计思想,跟具体用什么架构应该没有什么关系,DDD也需 ...
- 开始DDD
如何开始DDD(完) 连续写了两篇文章,这一篇我想是序的完结篇了.结合用户注册的例子再将他简单丰富一下.在这里只添加一个简单需求,就是用户注册成功后给用户发一封邮件.补充一下之前的代码 public ...
- Repository 仓储,你的归宿究竟在哪?(二)-这样的应用层代码,你能接受吗?
写在前面 关于"Repository 仓储,你的归宿究竟在哪?"这个系列,本来是想写个上下篇,但是现在觉得,很有多东西需要明确,我也不知道接下来会写多少篇,所以上一篇的标题就改成了 ...
- Repository 仓储,你的归宿究竟在哪?(一)-仓储的概念
写在前面 写这篇博文的灵感来自<如何开始DDD(完)>,很感谢young.han兄这几天的坚持,陆陆续续写了几篇有关于领域驱动设计的博文,让园中再次刮了一阵"DDD探讨风&quo ...
- Repository 仓储,你的归宿究竟在哪?(上)
Repository 仓储,你的归宿究竟在哪?(上) 写在前面 写这篇博文的灵感来自<如何开始DDD(完)>,很感谢young.han兄这几天的坚持,陆陆续续写了几篇有关于领域驱动设计的博 ...
- DDD领域驱动设计落地实践(十分钟看完,半小时落地)
一.引子 不知今年吹了什么风,忽然DDD领域驱动设计进入大家视野.该思想源于2003年 Eric Evans编写的"Domain-Driven Design领域驱动设计"简称DDD ...
- 遗留系统如何用DDD重构(未完,待续)
GETTING DDD STARTED SURROUNDED BY LEGACY SYSTEMS ByEric Evans
- 如何一步一步用DDD设计一个电商网站(十)—— 一个完整的购物车
阅读目录 前言 回顾 梳理 实现 结语 一.前言 之前的文章中已经涉及到了购买商品加入购物车,购物车内购物项的金额计算等功能.本篇准备把剩下的购物车的基本概念一次处理完. 二.回顾 在动手之前我对之 ...
- 如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文
阅读目录 前言 明确业务细节 建模 实现 结语 一.前言 上一篇我们已经确立的购买上下文和销售上下文的交互方式,传送门在此:http://www.cnblogs.com/Zachary-Fan/p/D ...
随机推荐
- photoshopcc基础教程
web项目中,除了最基础的用java存取数据外,还有重要的h5+css排版以及图片的ps,排版多多看网上人家的好看的界面设计,至于图片,只能自己上手了,设计最终的目的是好看,好看,好看. 接下来,做个 ...
- ServiceStack.OrmLite中的一些"陷阱"(3)
前文说到如果使用多数据库(不同SQL方言)时要如何开发?其实前文(第二篇)也有“透露”到.就是直接使用库提供的OrmLiteConnection 及OrmLiteConnectionFactory(I ...
- UrlPager免费分页控件2.0版发布!
UrlPager是一个ASP.NET WebForm应用程序中通过url进行分页的分页控件,支持使用url路由来生成自定义的分页url.与AspNetPager不同,UrlPager需.NET Fra ...
- hibernate配置文件中的schema="dbo"在MySQL数据库不可用
把项目的数据库由SQL Server更改为MySQL之后,发现hibernate报错. 问题在于schema="dbo",使用SQL Sever数据库时正常,使用MySQL数据库需 ...
- linux系统编程之错误处理
在linux系统编程中,当系统调用出现错误时,有一个整型变量会被设置,这个整型变量就是errno,这个变量的定义在/usr/include/errno.h文件中 #ifndef _ERRNO_H /* ...
- 【转】Beanstalkd 队列简易使用
Beanstalkd一个高性能分布式内存队列系统 之前在微博上调查过大家正在使用的分布式内存队列系统,反馈有Memcacheq,Fqueue, RabbitMQ, Beanstalkd以及link ...
- nodeJS express框架 中文乱码解决办法
最近在研究javascript 的服务端应用 node,之所以想要研究node,是因为前几个月一直在前端挣扎,从javascript入门到在项目中实际使用javascript,确实感悟颇深.javas ...
- (多重背包+记录路径)Charlie's Change (poj 1787)
http://poj.org/problem?id=1787 描述 Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie dri ...
- HTML5中id可以用数字开头,但在css中不能正常使用
昨晚在看<响应式Web设计:html5和css3实战>时,书中提到“HTML5中的ID指可以用数字开头”.这个还真不知道,于是测试了一下,发现了问题. 在H5描述中是这样说的: 在css样 ...
- maven 简介
本书代码下载 大家可以从我的网站下载本书的代码:http://www.juvenxu.com/mvn-in-action/,也可以通过我的网站与我取得联系,欢迎大家与我交流任何关于本书的问题和关于Ma ...