连续写了两篇文章,这一篇我想是序的完结篇了。结合用户注册的例子再将他简单丰富一下。在这里只添加一个简单需求,就是用户注册成功后给用户发一封邮件。补充一下之前的代码
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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
2013-08-06 Kemaswill 机器学习 数据挖掘 推荐系统 Ranking SVM 简介
2013-08-06 基于WF4.0的公文管理系统
2013-08-06 指针的本质
2013-08-06 查找算法---find运算,find_first_of的使用
2013-08-06 Java集合概述、Set集合(HashSet类、LinkedHashSet类、TreeSet类、EnumSet类)
2013-08-06 .NET:再论异常处理,一个真实的故事
2013-08-06 前端开发的使用服务器环境开源项目 D2Server 可替代Apache