开始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就会监听并处理此事件。上面的代码可能阅读理解起来不是那么的直白,具体的实现起来也并非就这么简单,只是提出一种方法。具体实现我的开源代码里也有相关例子http://thinknet.codeplex.com
总结
以上三篇文章我也主要是从写代码的角度去介绍如何DDD,强调一下我不是在教你如何写代码,只是为了展示用DDD如何实现,领域里的模型更应该能表达业务,他的价值更并不仅于此。而且以上的描述不一定完全正确,也不是告诉你一定要如何做,这也需要你自己的思考,如果有不对的地方欢迎你的指正,毕竟DDD我在学习过程中,也能从中受益。
如果我们过多的精力花在如何写代码上,可能是收集的工具类库还不强大,或者是还没有一个能够方便快捷开发的框架,当然一个好的框架带来的好处会很多。一个框架终究是有办法和技术能力去实现完成的,但是如何分析和理解业务,然后从中挖掘出便于阅读和表达业务的模型确定一件不容易的事情,他并不是通过某种技术办法就能实现的。所以我个人觉得设计模型,划分界限上下文是需要不断的积累领域业务知识才能做到的。
“领域驱动设计”和“实现领域驱动”这两本书应该是最经典的了,知识点也很多,阅读此书你会得到更多的收获!
随笔分类 - ThinkNet
开始DDD的更多相关文章
- 如何一步一步用DDD设计一个电商网站(九)—— 小心陷入值对象持久化的坑
阅读目录 前言 场景1的思考 场景2的思考 避坑方式 实践 结语 一.前言 在上一篇中(如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成),有一行注释的代码: public interfa ...
- 如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成
阅读目录 前言 建模 实现 结语 一.前言 前面几篇已经实现了一个基本的购买+售价计算的过程,这次再让售价丰满一些,增加一个会员价的概念.会员价在现在的主流电商中,是一个不大常见的模式,其带来的问题是 ...
- 如何一步一步用DDD设计一个电商网站(十)—— 一个完整的购物车
阅读目录 前言 回顾 梳理 实现 结语 一.前言 之前的文章中已经涉及到了购买商品加入购物车,购物车内购物项的金额计算等功能.本篇准备把剩下的购物车的基本概念一次处理完. 二.回顾 在动手之前我对之 ...
- 如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念
一.前言 DDD(领域驱动设计)的一些介绍网上资料很多,这里就不继续描述了.自己使用领域驱动设计摸滚打爬也有2年多的时间,出于对知识的总结和分享,也是对自我理解的一个公开检验,介于博客园这个平 ...
- 如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文
阅读目录 前言 明确业务细节 建模 实现 结语 一.前言 上一篇我们已经确立的购买上下文和销售上下文的交互方式,传送门在此:http://www.cnblogs.com/Zachary-Fan/p/D ...
- 如何一步一步用DDD设计一个电商网站(六)—— 给购物车加点料,集成售价上下文
阅读目录 前言 如何在一个项目中实现多个上下文的业务 售价上下文与购买上下文的集成 结语 一.前言 前几篇已经实现了一个最简单的购买过程,这次开始往这个过程中增加一些东西.比如促销.会员价等,在我们的 ...
- 如何一步一步用DDD设计一个电商网站(五)—— 停下脚步,重新出发
阅读目录 前言 单元测试 纠正错误,重新出发 结语 一.前言 实际编码已经写了2篇了,在这过程中非常感谢有听到观点不同的声音,借着这个契机,今天这篇就把大家提出的建议一个个的过一遍,重新整理,重新出发 ...
- 如何一步一步用DDD设计一个电商网站(四)—— 把商品卖给用户
阅读目录 前言 怎么卖 领域服务的使用 回到现实 结语 一.前言 上篇中我们讲述了“把商品卖给用户”中的商品和用户的初步设计.现在把剩余的“卖”这个动作给做了.这里提醒一下,正常情况下,我们的每一步业 ...
- 如何一步一步用DDD设计一个电商网站(三)—— 初涉核心域
一.前言 结合我们本次系列的第一篇博文中提到的上下文映射图(传送门:如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念),得知我们这个电商网站的核心域就是销售子域.因为电子商务是以信息网络 ...
- 如何一步一步用DDD设计一个电商网站(二)—— 项目架构
阅读目录 前言 六边形架构 终于开始建项目了 DDD中的3个臭皮匠 CQRS(Command Query Responsibility Segregation) 结语 一.前言 上一篇我们讲了DDD的 ...
随机推荐
- IP地址解析
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.N ...
- ios7 JavaScriptCore.framework
曾经想要oc调用js代码通常是通过uiwebview的stringByEvaluatingJavaScriptFromString方法,或是直接使用JavaScriptCore引擎,比如https:/ ...
- POJ 1113 || HDU 1348: wall(凸包问题)
传送门: POJ:点击打开链接 HDU:点击打开链接 以下是POJ上的题: Wall Time Limit: 1000MS Memory Limit: 10000K Total Submissio ...
- SPOJ 375 树链剖分
SPOJ太慢了,SPOJ太慢了, 题意:给定n(n<=10000)个节点的树,每条边有边权,有两种操作:1.修改某条变的边权:2.查询u,v之间路径上的最大边权. 分析:树链剖分入门题,看这里: ...
- 一旦rhel5.8造成只读文件系统ORA-00354: corrupt redo log block header
一旦rhel5.8造成只读文件系统ORA-00354: corrupt redo log block header Wed Jun 03 03:31:24 CST 2015 Thread 1 adva ...
- HDU ACM 1007 Quoit Design 分而治之的方法,最近点
意甲冠军:给n坐标点.半一对点之间的距离所需的距离最近. 分析:分而治之的方法,最近点. #include<iostream> #include<algorithm> #inc ...
- 面向对象三大特征之多态——Java笔记(七)
多态: 同一个实体同时具有多种形式 编译时的类型有声明该变量时使用的类型决定,运行时的类型有实际赋值给变量的对象决定 如果编译时类型和运行时类型不同,就出现多态 例: clas ...
- js 正则学习小记之NFA引擎
原文:js 正则学习小记之NFA引擎 之前一直认为自己正则还不错,在看 次碳酸钴,Barret Lee 等大神都把正则玩的出神入化后发现我只是个战五渣. 求抱大腿,求大神调教. 之前大致有个印象,正 ...
- 什么时候rootViewController至tabbarController时刻,控制屏幕旋转法
于ios6后,ios系统改变了屏幕旋转的方法,假设您想将屏幕旋转法,在需求rootvc里面制备,例如 UIViewController *viewCtrl = [[UIViewController a ...
- mac_Mac item2常用快捷键
整理使用 iTerm 2 过程中得常用快捷键,Mac 原来自带的终端工具 Terminal 不好用是出了名的,虽然最近几个版本苹果稍微做了些优化,功能上,可用性方面增强不少,无奈有个更好用的 Iter ...