DDD 应对具体业务场景,Domain Model 重新设计
2014-07-08 12:54
597 查看
DDD 应对具体业务场景,Domain Model 重新设计
写在前面
上联:no zuo no die why you try 下联:no try no high give me five 横批: let it go上联:no zuo no die why you cry 下联:you try you die don't ask why 横批: just do it
阅读目录:
自作自受
迷雾中的探照灯
我的错,我承认
再次出发
开源地址
后记
上面那幅对联前段时间在网上还蛮火的,意思大家意会就可以了,这边就不翻译了,我个人理解,所表达的个性就是:in my life,no zuo no die。
为什么会引入这个流行语?因为在应对具体业务场景,进行领域驱动设计的时候,整个项目的设计实现过程,所表达的就是这个意思:不作不死。
我的“第一次”,就这样没了:DDD(领域驱动设计)理论结合实践:伪领域驱动设计,只是用 .NET 实现的一个“空壳”,仅此而已。
一缕阳光:DDD(领域驱动设计)应对具体业务场景,如何聚焦 Domain Model(领域模型)?:只是聚焦领域模型(认清各个部分的职责,让设计的焦点集中在领域模型中),文中关于领域模型的实现就是一个“渣”,仅此而已。
死去活来,而不变质:Domain Model(领域模型) 和 EntityFramework 如何正确进行对象关系映射?:走了个弯路,ORM 的映射关系及仓储的实现,应该是在本篇内容之后探讨,原因都是脚本驱动模式惹的祸,如果说脚本驱动模式是恶魔(特定的环境,也有好处,不能一概而论,这边只是一个比喻),那领域驱动设计可以看作是天使,心里想的是天使,却听了恶魔的话,为什么?因为它在你心中已根深蒂固,仅此而已。
拨开迷雾,找回自我:DDD 应对具体业务场景,Domain Model 到底如何设计?:在迷雾森林迷失那么久,自以为走了出来,其实是又走进了另一个迷雾森林,评论中和 netfocus 兄的讨论就证实了这一点。
自作自受
我曾在上一篇博文的最后这样写道:“可能几天或者几周后,看现在的这篇博文就像一坨屎一样”。这篇博文指的是《拨开迷雾,找回自我:DDD 应对具体业务场景,Domain Model 到底如何设计?》,现在看来,正被我说中了。先回顾一下,上一篇博文所探讨的内容:Domain Model 到底如何设计?毫无疑问,领域模型的设计是领域驱动设计最重要的部分,关于领域模型的设计,从一开始的不理解,把领域模型设计的很贫血,然后业务逻辑都实现在了应用层,后来经过反思,把造成这种设计误区的元凶,怀疑到了 Repository(仓储)身上(后来证实,人家是无辜的),然后针对仓储,引入了 Domain Service(领域服务),把业务逻辑转移到了领域服务中(后来证实,完全错误的引用),只是把 Application 单词变成了 Domain Service 这个单词,其他无任何变化,以至于工作流程逻辑和业务逻辑完全分不开。
造成以上的主要原因都是为了领域而领域,并没有实实在在的去思考业务逻辑和领域模型,后来认识到这个根本问题后,就抛开一切外在因素,比如领域服务、仓储、应用层、表现层等等,这些统统不管,只做领域模型的设计,让真正的设计焦点集中在领域模型上,然后再针对领域模型做单元测试。
上面的思路听起来是还蛮不错的,至少听起来是不错,在上一篇博文中,后来,我是这样“忽悠”大家的:
回到短消息系统-MessageManager,需要注意的是,我们做的是消息系统,一切的一切都应该围绕 Message 领域模型展开, 在这个系统中,最重要的就是发送消息这个业务逻辑,什么叫发消息?不要被上面的面向对象所迷惑,只考虑发消息这个具体的业务,我们来分析一下:比如在现实生活中,我们要给女朋友写信,首先我们要写信的内容,写完之后,要写一下女朋友的地址信息及名字,这个写信才算完成,邮递员邮递并不在这个业务逻辑之内了,因为这封信我写上收件人之后,这封信相对于我来说就已经发出了,后面只不过是收件人收不收得到的问题了(即使我写好,没有寄出去)。也就是说邮递员邮递这个工作过程相当于数据的持久化,写信的这个过程就是邮递(发消息的业务逻辑),just it。
观点富有辩证性,会让你认为“的确是这样啊”,呵呵。其实有一点我是说的不错,就是我们做的是短消息系统,一切的一切都应该围绕 Message 领域模型展开,消息领域模型中最重要的一个业务逻辑就是发消息(其他业务规则暂不考虑),那发消息的业务逻辑是什么?仅仅是我所固执的认为,往这条消息贴上一个收件人?你能接受吗?至少 netfocus 兄就不接受(具体请看上一篇博文评论),按照这种设计思路,消息领域模型的设计代码如下:
View Code
发送消息领域服务:
View Code
消息应用服务:
View Code
这边再简单描述下发送消息这个业务流程实现,其实看下应用层的代码就清楚了,首先,UI 发送一个发消息的请求给应用层(相当于系统),参数为:标题、内容、发送人登录名、收件人显示名,应用层服务接到请求之后,先根据发送人和收件人的名称去仓储中查找相对应的用户,如果用户不存在,直接越过下面的发送操作,如果用户存在,则创建一个消息对象,在消息实体的构造函数中去验证这些参数的规则(比如参数不为空、字符串长度限制等等),如果验证成功则创建消息对象成功,首先这这一方面的改进之处就是,把收件人的赋值操作放在这边了,发送消息这个业务逻辑的体现其实并不是简单的赋值操作,其实这种实现更符合实际生活,比如我写一封信给女朋友,写好标题、内容、收件人和发件人之后,我并没有寄出,但是这封信已经存在了(符合信存在的标准),但是没有寄出,也就是说这个消息对象已经存在,只是现在这个对象的状态是未寄出,关于这一点,其实是和之前的设计是完全不同的,具体不同我也就不说了。
换个行,要不然看着太费劲。我们接着说,消息对象创建成功之后(状态是未发),调用发送消息领域服务,进行业务规则验证(比如发送人不能和收件人相同,发送人一天之内不能发送超过100个的短消息等等),其实这才是真正的发送消息业务逻辑,正如领域服务所定义的那样,参数和返回值都是领域对象,也就是消息实体,发送验证成功后进入持久化或者基础服务发送邮箱,整个发送消息的工作流程就是这样。
在上述发送消息工作流程描述中,需要注意的最重要的一点,就是消息状态的体现,也就是消息对象的未发状态和已发状态,这两个状态确定的前提这个消息对象是存在的,也就是创建成功的。在以前的设计中,如何体现这个发送状态的确定?答案就是收件人的赋值,之前认为,只有填写了收件人,那这个消息的状态就是已发送,其实这种逻辑有点天马星空。我现在个人感觉,消息对象的发送状态不能由它自身确定,也就是说不能由它自己的某一个属性确定,它应该是一个动态的过程,也就是在验证发送业务规则成功后,retrun 之后的那个消息对象,表示这个消息对象的状态是已发送的,因为它是符合发送消息业务规则并验证通过,那它的状态就是已发送。
开源地址
GitHub 开源地址:https://github.com/yuezhongxin/MessageManagerASP.NET MVC 发布地址:http://www.xishuaiblog.com:8081/
ASP.NET WebAPI 发布地址:http://www.xishuaiblog.com:8082/api/Message/GetMessagesBySendUser/小菜
后记
关于领域驱动设计实践的博文,也写了几篇,但是说句实在话,是有点对不住大家,因为下一篇都在为上一篇做一些解释或更正,希望大家在看得过程中保留一下自己的想法,不要被我给忽悠了。关于这一篇的内容,其实我现在已经做好下一篇更正的准备了,呵呵。
下一步的计划是我是这样想的:现在一个发送消息用例基本上差不多了(可能还存在其他问题),然后接下来按照这种模式把其他消息用例加进来(比如消息回复、查看等等),看看会发生什么情况,可能会出现一大堆问题,这也是我想要的,与其有针对性的解决问题,总比苦思冥想的思考要好很多。
MessageManager 项目设计到现在是没有数据库的(no datebase),在下面的开发设计过程中也会坚持这一原则。以前开发模式都是先根据需求建立表结构,然后再围绕数据库用面向对象语言做 SQL 的搬运工。可以幻想下,如果开发一个项目,在开发设计的过程中,完全没有数据库的概念(数据库在开发完成之后生成,只是数据存储的一种方式),会是什么感觉呢?我想那应该很奇妙。
如果你觉得本篇文章对你有所帮助,请点击右下部“推荐”,^_^
参考资料:
http://gorodinski.com/blog/2012/04/14/services-in-domain-driven-design-ddd/
相关文章推荐
- No zuo no die:DDD 应对具体业务场景,Domain Model 重新设计
- No zuo no die:DDD 应对具体业务场景,Domain Model 重新设计
- 一缕阳光:DDD(领域驱动设计)应对具体业务场景,如何聚焦 Domain Model(领域模型)?
- 拨乱反正:DDD 回归具体的业务场景,Domain Model 再再重新设计
- DDD(领域驱动设计)应对具体业务场景,Domain Model(领域模型)到底如何设计?
- DDD 回归具体的业务场景,Domain Model 再再重新设计
- 拨开迷雾,找回自我:DDD 应对具体业务场景,Domain Model 到底如何设计?
- 拨开迷雾,找回自我:DDD 应对具体业务场景,Domain Model 到底如何设计?
- DDD(领域驱动设计)应对具体业务场景,如何聚焦 Domain Model(领域模型)?
- 来自 Repository 的一丝线索,Domain Model 再重新设计
- 架构师如何应对复杂业务场景?领域建模的实战案例解析
- 架构师如何应对复杂业务场景?领域建模的实战案例解析
- 架构师如何应对复杂业务场景?领域建模的实战案例解析
- 贫血模型;DTO:数据传输对象(Data Transfer Object);AutoMapper ;Domain Model(领域模型);DDD(领域驱动设计)
- Domain Model:业务对象的进一步设计2
- Domain Model:业务对象的进一步设计2
- 设计窘境:来自 Repository 的一丝线索,Domain Model 再重新设计
- 设计窘境:来自 Repository 的一丝线索,Domain Model 再重新设计
- DDD 领域驱动设计-看我如何应对业务需求变化,领域模型调整?