4 实体的形态
4.1 业务形态
战略设计时,实体是领域模型的一个重要对象。领域模型中的实体是多个属性、操作或行为的载体。
事件风暴中,可根据命令、操作或者事件,找出产生这些行为的业务实体对象,进而按业务规则将依存度高和业务关联紧密的多个实体对象和值对象进行聚类,形成聚合。
实体和值对象是组成领域模型的基础单元。
4.2 代码形态
即实体类,包含实体的属性和方法,通过这些方法实现实体自身的业务逻辑。
采用充血模型:
- 该实体相关的所有业务逻辑都在实体类的方法中实现
- 跨多个实体的领域逻辑则在领域服务中实现
4.3 运行形态
实体以DO(领域对象)形式存在,每个实体对象都有唯一ID。可对实体做多次修改,所以一个实体对象可能和它之前状态存在较大差异。但它们拥有相同身份标识(identity),所以始终是同一实体。
比如商品是商品上下文的一个实体,通过唯一的商品ID标识,不管这商品的数据(比如价格)如何变,商品ID不会变,始终是同一商品。
4.4 数据库形态
DDD先构建领域模型,针对业务场景构建实体对象和行为,再将实体对象映射到数据持久化对象。
在领域模型映射到数据模型时,一个实体可能对应0、1或多个数据库持久化对象。大多数情况下实体与持久化对象是一对一。在某些场景中,有些实体只是暂驻静态内存的一个运行态实体,无需持久化。比如,基于多个价格配置数据计算后生成的折扣实体。
有些复杂场景,实体与持久化对象可能是一对多或多对一:
一对多
用户user与角色role两个持久化对象可生成权限实体,一个实体对应两个持久化对象
多对一
有时为避免DB的联表查询,会将客户信息customer和账户信息account两类数据保存至同一张数据库表,客户和账户两个实体可根据需要从一个持久化对象中生成
实体本质的探索
一开始在Java代码中建模大量实体关系。将太多关注点放在数据库、表、列和对象映射上。导致所创建的模型实际上只是含有大量getter/setter的贫血领域模型。
我们应该在DDD 上有更多的思考。
如果我们认为对象就是一组命名的类和在类上定义的操作,除此之外并不包含其他内容,那就错了。
如果一些特定的领域场景会在今后继续使用,这时可以用一个轻量的文档将它们记录下来。简单形式的通用语言可以是一组术语和一些简单的用例场景。 但是,如果我们就此认为通用语言只包含术语和用例场景,那么我们又错了。在最后,通用语言应该直接反映在代码中,而要保持设计文档的实时更新是非常困难的,甚至是不可能的。