关于DDD中Domain的思考

本文既不推销UML,也不推广DDD,更不涉及各种论战。-- 作者

某天又一次打开关于DDD(领域驱动设计)的PDF文档时,自己有了个疑问:什么是领域(Domain)?译文中是这样描述领域:银行业务被银行的内部人员和专家所熟知。他们知道所有的细节、所有的困难、所有可能 出现的问题、所有的业务规则。这些就是我们永远的起始点:领域。如果这就是领域,它似乎不是"起始点",而是“全部”--全部的业务规则、全部的细节、全部可能出现的问题。我的疑问正是始于此:Domain映射到软件,"全部"不就是整个系统?

这里有个概念漏洞,Domain是"全部",但不是全世界的"全部",那它是什么的全部?显然,译文中看到的"银行业务",其对应的Domain也不是指银行业务系统的全部,因此Domain的概念相对清晰--一个有清晰边界、内部的业务、规则、问题、细节都自成一派--你会问我,这是指对象(Object)吧!如果从低层次上讲,两者是有关系的。下一个疑问:Domain和Object有什么不同?

我思考的结果是封装的级别不同:Object封装的目标是调用其方法实现所承诺的功能,但系统中的对象是有依赖的;Domain封装的目标是"全部"都在这里,即不需要依赖其他的Object或者Domain。之所以这么想,主要的依据是从那个常用的例子:机场、航线、飞机,虽然我看的译文中把这三个定义为对象,使用UML画了聚合关系;我更倾向于把它们看成Domain,即我认为机场不会调用飞机的方法(或者人),两者只是相互关注了对方(的事件)。例如,飞机A1和机场B1通过无线电沟通(消息)。Object间的消息一般是带着发送者或者接受者的数据,也就是A1发送的是B1要处理的;而Domain间的消息是否处理,如何处理则是完全由接收者自己处理,发送者也不关心消息的处理。再一个疑问:如何达到"全部"封装?

上面的例子中,我使用了"事件"这个关键字。事件(消息)不是新鲜事物,在面向对象的系统中,其作为异构子系统、系统间异步调用的桥梁,起着重要的作用;所以我认为“事件通知”不是实现Domain的途径,因为它是同步调用的变种:消息的生产者和消费者仍然有业务逻辑上的天然联系。事件除了通知,还有一种模式是监听。这样事件是一种公共资源,是开放的标准,不论采用广播、总线、管道各种模式,Domain监听自己关注的事件,并对其进行响应,如果产生了新的("开放")事件,则将事件发布回(广播、总线、管道的)‘通道‘。以机场和飞机为例,机场广播的跑道天气咨询,飞机的飞行员如果关心,则通过无线电接听,如果不关心,则完全可以关闭无线电。

以上基本展示了我思考的过程。其间,我回顾了自己使用过的各种(X)O,(X)O包含面向服务(架构)-SO(A),面向方面(编程)-AO(P),面向对象-OO,面向过程-PO。

粗略地得到了下图:

从上图中除了有关于Domain的思考,还想了关于如何更好的使用各种方法论。我有个观点:同步就是两次或者多次异步交互的集成。

画图的过程中,我又有了个疑问:服务间的异步通知类接口,是否是实现Domain的一种形态?通过与分布式服务系统的拆分,我认为:异步通知(接口)是一种补充,而不是Domain间交互的主要方式,它类似“塔台呼叫711,711听到请回答”;如果全程都是这样飞行,塔台需要为每个飞机配置一个导航员,且每个飞机独立使用一个频率,这不是一个好设计,尽管它在航空管制初期可能是可行的。

我的结论是:面向领域设计DDD中的领域是比对象、服务更加高度的封装,领域包含自己的数据、行为、控制等"全部",并对外部事件(或者消息)做出响应,按照自己的规则完成特定的功能。基于这样的特点,Domain间的通讯应该是异步事件监听模式。

时间: 2024-08-24 07:33:08

关于DDD中Domain的思考的相关文章

(DDD)仓储的思考

(DDD)仓储的思考 为什么需要仓储呢?领域对象(一般是聚合根)的被创建出来后的到最后持久化到数据库都需要跟数据库打交道,这样我们就需要一个类似数据库访问层的东西来管理领域对象.那是不是我们就可以设计一个类似DAL层的东东来管理对象呢?是的,但是呢设计上有点区别,就是我们不希望上层如应用层直接访问数据,我们所有的操作应该是围绕着领域对象来的,所以我们还设计了仓储接口在领域层,然后把仓储的实现放在基础设施层.这样的设计模式很常见,一般用来解耦的.但是仓储不处理事务,事务处理我们一般交给UnitOf

初探领域驱动设计(2)Repository在DDD中的应用

概述 上一篇我们算是粗略的介绍了一下DDD,我们提到了实体.值类型和领域服务,也稍微讲到了DDD中的分层结构.但这只能算是一个很简单的介绍,并且我们在上篇的末尾还留下了一些问题,其中大家讨论比较多的,也是我本人之前有一些疑问的地方就是Repository.我之前觉得IRepository和三层里面的IDAL很像,为什么要整出这么个东西来:有人说用EF的话就不需要Repository了:IRepository是鸡肋等等. 我觉得这些问题都很好,我自己也觉得有问题,带着这些问题我们就来看一看Repo

ORM中的Model与DDD中的DomainModel

0.引言 在现有的系统开发中,大部分的系统应该都会用到ORM,无论用的是EF还是NHibernate.作为对象和持久化数据的桥梁,ORM确实非常方便,以至于在DDD的时候,我们很自然的将 ORM中的Model(实体)表达成DDD中的 DomainModel(领域对象). 但这真的合理吗?我们先引入两个例子来探讨这个问题. 1.例子1:订单聚合 下述聚合引自汤神的博客: 我们看以上的聚合设计非常经典.Order对象作为聚合根,OrderItem建模成实体,只要在当前的订单聚合中不重复即可. 但在真

于《黑客与画家》中的独立思考所想到的

中国科学技术大学软件学院  高志鹏  原创作品转载请注明出处 <黑客与画家>由于是美国互联网界举足轻重.有“创业教父”之称的哈佛大学计算机博士保罗•格雷厄姆(Paul Graham)所著,所以大家对这本书也是一致的如潮的好评.说实话,这本书我并没有看完,而且可能由于国内环境和美国环境的差异,作者的很多观点我也并没有产生很强烈的共鸣.但是,作者在本书中对独立思考和批判性思维的推崇使我的感触颇多. 其实我真正意识并重视独立思考这种能力是在我接触知乎这个社区以后(这里也顺便给知乎打个广告,是个很不错

关于C++类静态成员在Delphi中实现的思考

关于C++类静态成员在Delphi中实现的思考 没有用过Version 7 以后的Delphi版本,即便5.6.7版本,我也不能够说了解较深.因此,本文可能杞人忧天. 一.为什么需要静态成员 比如:一个类,常常需要创建多个对象,我们经常需要得到这些对象的Count:再如:在类似链表中,我们需要标识它的头部.这些信息,都需要供给所有对 象共享(甚至类).不可能把信息放到类中去,因为类不占有内存空间:不能够用全局变量,这将破坏类的封装:如果放到对象中去,又显然不现实:当某一个对象 发生改变时,要逐一

你的MySQL服务器开启SSL了吗?SSL在https和MySQL中的原理思考

最近,准备升级一组MySQL到5.7版本,在安装完MySQL5.7后,在其data目录下发现多了很多.pem类型的文件,然后通过查阅相关资料,才知这些文件是MySQL5.7使用SSL加密连接的.本篇主要介绍MySQL5.7 SSL连接加密功能.如何使用?以及使用SSL的一些注意点. 我们知道,MySQL5.7之前版本,安全性做的并不够好,比如安装时生成的root空密码账号.存在任何用户都能连接上的test库等,导致数据库存在较大的安全隐患.好在5.7版本对以上问题进行了一一修复.与此同时,MyS

关于领域驱动设计(DDD)仓储的思考

为什么需要仓储呢?领域对象(一般是聚合根)的被创建出来后的到最后持久化到数据库都需要跟数据库打交道,这样我们就需要一个类似数据库访问层的东西来管理领域对象.那是不是我们就可以设计一个类似DAL层的东东来管理对象呢?是的,但是呢设计上有点区别,就是我们不希望上层如应用层直接访问数据,我们所有的操作应该是围绕着领域对象来的,所以我们还设计了仓储接口在领域层,然后把仓储的实现放在基础设施层.这样的设计模式很常见,一般用来解耦的.但是仓储不处理事务,事务处理我们一般交给UnitOfWork,有关于Uni

探讨DDD中角色权限与DCI的使用

本文初衷 之前在学习DDD的时候,一直被权限与角色困扰. 我们知道在Asp.net MVC 的Controller或Action加上特性标签[Authorize],就可以实现权限控制. [Authorize(Roles ="Manager")] public class MainController : Controller { // GET: Main public ActionResult Index() { return View(); } } 但是在应用层中,如何使用好角色?在

从Entity Framework的实现方式来看DDD中的repository仓储模式运用

一:最普通的数据库操作 static void Main(string[] args) { using (SchoolDBEntities db = new SchoolDBEntities()) { db.Students.Add(new Student() { StudentName = "nihao" }); db.SaveChanges(); } } domain 和 db 是怎么操作... DbSet<Student> 集合 [用于存放集合] 从名称中可以看出,是