上一节讲到领域模型分为两层
一层是抽象层,定义了公共的接口和类
另一层就是领域模型的定义层
先看一下抽象层的定义
1、实体接口 IEntity
通常情况下实体只有一个 ID,但是也不排除存在多个 ID 的情况,所以这里的接口 IEntity 定义实现为多个 ID 的情况,而 IEntity 表示实体只有一个 Id
同样看一下 Entity 的定义
同样地定义了一个 Entity 和 Entity,这样就可以在实体上面定义一些共享的方法,比如 ToString
对于 Entity 定义了比较多的方法
2、聚合根接口 IAggregateRoot
聚合根接口实际上是一个空接口,它不实现任何的方法,它的作用是在实现仓储层的时候,让一个仓储对应一个聚合根
3、领域事件接口 IDomainEvent
4、域事件处理接口 IDomainEventHandler
5、还有一个领域模型里面比较关键的值对象 ValueObject
值对象的定义比较特殊,因为它是没有 Id 的,所以没有关于 Id 的定义,并且没有对值对象定义接口
重点实现了它是否相等的判断,也是重载了 Equals 这个方法和 GetHashCode 这个方法
它有一个特殊的抽象方法的定义,获取它的原子值
这个方法的作用是将值对象的字段输出出来,作为唯一标识来判断两个对象是否相等,可以看到 Equals 的定义里面也是调用了获取原子值这个方法来判断它是否相等
接下来看一下定义的 Order 实体
它首先实现了 Entity,这一个在上一节已经讲过,另外一个 Order 定义为一个聚合根,它需要实现聚合根接口 IAggregateRoot
实体中字段的 set 设置为 private,这样的好处是 Order 所有的数据的操作都应该由实体负责,而不应该被外部对象去操作,从而让领域模型符合封闭开放的原则
对于领域模型的操作,都应该是定义具有业务逻辑含义的方法来定义
比如说 ChangeAddress,就定义一个 ChangeAddress 的方法,把新的地址传进来,由领域模型负责赋值
这里面就可以添加一些地址的校验,比如新的地址是否能够与旧的地址距离太远
看一下地址的定义
只能通过构造函数给值对象赋值,这里面需要注意的是重载了获取原子值的方法,使用了 yield return
总结一下
在定义领域模型的时候,首先领域模型的字段的修改应该设置为私有的
使用构造函数来表示对象的创建,它的初始值都是由构造函数的参数来赋值的
另外需要定义有业务含义的动作来操作模型的字段
领域模型只负责自己数据的处理,领域服务或者命令负责调用领域模型的业务动作
样就可以区分领域模型的内在逻辑和外在逻辑,使代码结构更加合理
GitHub源码链接:
https://github.com/witskeeper/geektime

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。
如有任何疑问,请与我联系 ([email protected]) 。