当你决定以恶搞领域概念是否是一个值对象时,你需要考虑他是否拥有以下特征:
- 它度量或者描述了领域中的一件东西
- 它可以作为不变量
- 它将不同的相关的属性组合成一个概念整体
- 当度量和描述改变时,可以用另一个值对象予以替换
- 它可以和其他值对象进行相等性比较
- 它不会对协作对象造成副作用
如果你试图将多个属性加在一个实体上,但这样却弱化了各个属性之间的关系,那么此时你便应该考虑将这些相互关联的属性结合在一个值对象中了。每个值对象都是一个内聚的概念整体,它表达了通用语言中的一个概念。如果其中一个属性表达了一种描述性概念,那么我们应该把该概念相关的所有属性集中起来。如果其中一个或多个属性发生了改变,那么可以考虑对整体值对象进行替换。
实体的唯一标识时不能改变的,这可以部分地通过值对象地不变性达到。此外,我们还可以从值对象地概念整体特性中得到好处,因为实体的唯一标识是根据通用语言来命名的,并且需要在一个实例中得到好处,因为实体的唯一标识是根据通用语言来命名的,并且需要在一个实例中包含所有的可以标识唯一标识的属性。然而,这里我们并不需要值对象的可替换性,因为我们不会替换聚合根的唯一标识。尽管如此,我们依然可以在聚合中使用值对象。此外,如果实体的唯一标识需要一些无副作用的行为,这些行为便可以在值对象上实现。
最小化集成
在所有的DDD项目中,通常存在多个限界上下文,这意味着我们需要找到合适的方法对这些上下文进行集成。当模型概念从上游上下文流入下游上下文中时,尽量使用值对象来标识这些概念。这样的好处时可以达到最小化集成,既可以最小化下游模型中用于管理职责的属性数目。使用不变的值对象使得我们做更少的职责假设。
保持值对象的不变性
只有主构造函数才能使用自委派性来设置属性值,除此之外,其他方法都不能使用setter方法。由于值对象中的所有setter方法都是私有的,消费方是没有机会直接调用这些setter方法的。这是保持值对象不变性的两个重要因素。
持久化值对象
持久化过程即是将对象序列化成文本格式或者二进制格式,然后将其保存到计算机磁盘中。
对象-关系映射(ORM,比如Hibernate)持久化机制是流行的。但是,使用ORM将每个类映射到一张数据库表,再将每个属性映射到数据库表中的列会增加程序的复杂性。