其实,在以前的Nature框架中已经描述了很多,不过,这里,仍是想完整的阐述一下其中的概念。
不过,确定比较简略,若是真的要深刻理解,仍是要读《领域驱动设计》《实现领域驱动设计》这两本书。
好啦,接下来进入正题。
首先是关于聚合的内容。咱们认为,相关联的一些事物,构成了一种叫作聚合的概念。好比,说到书,他就会有封皮,书名,每页书,做者等等等等。他们是聚合在一块儿的,说到书,就表明了那一堆东西。而书这个概念,咱们则称之为聚合。若是把每种东西抽象成类和引用的关系,则总会有一个东西在最上层,表达着总体的概念,咱们称之为聚合根。
那么,聚合是由什么构成的呢?值得一提的是,咱们如今在说的聚合的概念,是一种结构性质的东西,与之相对的,它不是一种流程。
而构成聚合的构件,咱们使用两个东西,实体,值对象。
什么是实体?什么是值对象?以个人语言能力,解释起来略困难了一点。这么说吧,实体的特色是,具备生命周期,在其生命周期之中,其内部状态可能会发生变化。可是,实体具备其惟一的标志,即便两个实体除了标志外全部属性均彻底相同,咱们也认为他们是两个实体。那么,这个标志是什么呢?这也是我最近才领悟的,这个标志,是值对象。说说值对象吧。值对象,如字面所述,是表示值的对象。它表示了一种值,那么,它就具有了这么几个特征。首先,它不会改变本身的一部分,或者说,它的状态不会变,由于它没有生命周期,因此,它没有状态。它要么,是这个值,要么是那个值,而不存在这个值能够被变为何的说法。其次,若是两个值对象的全部状态都相等了,那么,它们就是同一个值,这个与实体可以造成鲜明的对比。
那么,为何说实体的标志是值对象呢?曾经,咱们的框架中,为了通用,将实体的标志,设置成了字符串。这能够知足惟一ID的需求,并且,也有最佳实践告诉咱们,这样管理全部的表是好的。可是,在我以往的实践中就碰见过这种状况。有的记录是使用组合主键标志本身的惟一性的。固然,咱们能够经过添加一个惟一ID的方式来使其统一,但,这引发了两个后果。首先,这增长了复杂度,其次,事情不是这样的,而却偏要这样实现,后面会遇到麻烦,其实,也是增长了复杂度。而在读《实现领域驱动设计》时,里面强调的,即便只是一个字符串,其实,它也是一个值对象。这是咱们很容易混淆的一点,而值对象的引入,无疑,增长了咱们对值这一律念的掌控。我但愿在我此次的框架里,能够达到这一目的。最后说明一点,聚合根,必定是实体。
而聚合由实体和值对象构成,实体能够经过自身的方法改变自身的状态,而这些操做在聚合范围内,也表明着实现了聚合自身的业务。由此,聚合表达了本身所表明的业务的含义。
其实,这里,是有问题存在的。聚合是须要被持久化的东西,咱们须要长期得跟踪其生命周期,改变其状态。那么,它的持久化,和读取或者说加载是怎么进行的呢?是由仓储进行的。仓储对聚合的持久化进行支持。提供了有限的几个操做:建立,保存,删除,经过标志加载。而正如仓储的字面意思,仓储,是一个仓库,作储备只用。而其中存储的东西,就是聚合。这里还有几个东西须要注意,既然,仓储是操做聚合的东西,那么,仓储,就不会在聚合内部被调用。而聚合之间,也是相互独立或者说是离散的。聚合和聚合之间,并没有法直接相互操做,不然,他们就应该是一个聚合。
那,聚合之间的写做是怎么完成的呢?经过领域服务。那领域服务和聚合是什么样的关系呢?或者说,有什么类似或者不一样呢?聚合,表达了领域中的一些结构,他们有属性,有生命周期,会被长时间的维护。而领域服务,也表达了领域中的一些结构,所不一样的是,它没有属性,单纯的,提供服务。好比说,转帐。若是帐户是一个聚合的话,那么转帐这个操做就会牵扯至少两个聚合。显而易见,在聚合内部是没法完成这个操做,这里须要一个服务来协调两个帐户进行转帐,而这个服务,咱们则称之为领域服务。
在咱们团队的实践过程当中,老大最初定义的领域服务是面向用例的,而我认为的领域服务是构成领域的一部分,而面向用例的那部分,不过是相似门户的存在。不过,最近的一次实践老大妥协了,容许两种同时存在。而其实,面向用例的那部分,我在我以前的框架中,是定义为命令,与应用服务进行通讯的。
那么,什么是应用服务呢?
其实,应用服务是独立于领域以外的,它是面向应用的,面向用例的。咱们领域中的模型并不能直接在应用中使用,由于应用要的不必定是他,他不必定够。因此,在应用服务中,会把领域中的东西,组装成应用想要的东西,再丢给应用。应用服务,大概就是这样的用处,转发,同时,也可以防止领域被应用所腐蚀。
其实,这里,还有两个构造块咱们没有说,领域事件,查询。
先说说领域事件吧。还以上面转帐的例子来讲,这,其实,是发生了一件事情。事实上来讲,它除了把钱从一个帐户转到另外一个帐户外,还记录下了转帐的流水。这是这个服务自己作的事情。而事实上,在以后,咱们为了可以更加清晰的对系统进行监控,咱们引入了日志。这里,是须要记录日志的。怎么记?修改原来的服务?能够。只是,彷佛存在如下的问题。开闭原则,咱们修改了原来的代码。单一职责原则,服务不只要进行本身的业务,还要记录日志。高内聚低耦合,原来的服务须要认识并使用日志模块,看样子,日志模块会变得无所不在。那么,咱们彷佛看到,随着系统内容和复杂度的增长,这将会是一种灾难。但是,咱们发现,事情并非这个样子的。其实应该是,转帐这件事发生了,由于这件事的发生,相关系统要进行对应的操做,好比,日志系统要记录日志。那么,发生的这件事,就是领域事件。领域事件的实现通常是发布订阅的模式来实现的,咱们这里也是,这彷佛是很天然的一件事情。
剩下的构造块,我称之为,查询。这个,是我在读了cqrs以后,引入的一个构造块。不了解的你们能够查一下cqrs的东西,之后有时间的话,我会整理一篇cqrs的文章。而cqrs采用事件溯源重构聚合,用领域事件更新查询源,供应用查询。而其解决的主要问题是,在经典DDD中,对业务的查询,是复杂的,低效的,由于应用须要的查询每每和领域自身的结构冲突,从而致使,连表查询,致使查询复杂度上升,效率下降。而起推崇以响应领域事件来维护一个供应用查询的数据源,而这个数据源中的数据,是咱们为了知足应用的查询,而维护在那里的。值得注意的是,咱们并无定义新的构造块给这些数据,他们依然是,聚合,其实更接近dto,虽然有些不天然,可是,也算知足了咱们的须要。另外,咱们能够经过属性,来对这些数据进行查询。