对值对象的理解

DDD中实体对象与值对象的解释比较抽象。 主要根据持续性与ID识别来区分。
但ID并非某一元素的直观自然属性, 而是经过分析建模之后确定了实体类,然后赋给实体类来达到跟踪,区别,存储目的的一个特值。 而在分析之前,如何判断一个概念是否有ID,这才是难点。

结合项目实践及DDD一书中的理论,感觉应该从以下几方面分析:

1. 某一概念是主动还是从属性的。如果是从属性的,且这种从属性的生命周期严格依赖于某实体,如可以考虑成为值对象的候选。

2. 某一概念是否可以被复用,共享,复制。象对应领域属性,规格,策略,规则的类,虽然对其他实体类的依赖性不是很强,可以独立存在。可以被不同的实体对象(不是指类)共享,复制,复用。如人的地址属性, 画笔的颜色字体属性,语言级别如string字符串。

3. 值对象创建后的作用:
3.1 往往是做为临时对象来进行计算,得出同类型的新值对象。来给实体对象业务使用。如创建查询标准这一临时对象,将此查询标准与其他查询标准组合,生成新查询标准, 给业务应用来进行过滤或查询。
3.2 创建做为临时对象来作为实体的业务行为的一个参数,以给业务行为提供验证检验审核某一规则或是特征之用
3.3 值对象提供的一些组合方法一般满足闭包特征:即 vo.add(VO anotherVO),vo.minus(VO anotherVO)都反回另一值对象。

4. 值对象的存储和与其相关联的实体类存储,由实体类来负责实体类的存储。通过设置实体对类与值类的级联关系。来达到实体类负责值对象的存储管理。


对于banq举例jj3中的 forumState为值对象,我存在疑问,因为forumState应该需要保存吧?比如某一时期的最高发贴数(这只属推测,JJ3源码的阅读正在日程表上,但现在还不了解)。


[该贴被boycott于2008-06-20 16:22修改过]

楼主分析得很好。

是否有ID确实是难点:比如有时很多类别特征作为值对象,比如发动机的规格V6,功率等是值对象,而某个具体的V6发动机有发动机编号,生产日期,并具备V6发动机通用规格属性。但是如果我们将V6规格作为一个类别来分类,那么就有ID了,这时我们到底应该将其作为实体还是值对象呢?

我的理解是这取决于具体的应用,如果这个领域只负责装配发动机,不需要区别哪个配件是哪个,这个配件就是值对象,如果领域需要维修发动机,并记录哪个配件发生过什么故障,做了哪些修理,反馈情况如何等等,这些配件显然就需要被记录,这时候就是实体。
按某类别分类,如果不允许一个东西同时拥有两个类别,按某个类别查询也要求查到的东西必须属于这个类别,就说明这些类别是需要被区分的,就是实体。
[该贴被freebox于2008-06-23 15:13修改过]

谢谢banq。

在我们的项目实际分析设计中,其实不用严格区分实体对象和值对象,用四色图来分析和理解更易接受。

值对象的作用应该主要集中在两方面:

1. 造成无负作用函数:因为值对象往往是动态生成的临时对象,其作用主要是提供一个规格或策略或特性而已, 所以对实体的类状态不产生影响。
但一定注意,代表计算,规格,策略或属性的值对象,作用是为实体对象修改其状态而生成的。 也就是说值对象只负责计算改变的值,而不真正实施改变。而真正的改变由实对象自己调用其他方法来进行。 这样使得计算和改变两个职责解耦,不联系在一起。 有几方面好处:

比如可以更改计算或规格策略,而不影响实体类; 不用跟踪计算的中间状态; 中间状态与修改状态无关。 所以我们可以放心使用值对象来计算。 因为它并不真正来影响实体类的状态,只是为状态改变提供值而已。可以提高程序性能,一般不用持久化值对象。

2. 在类之间关联关系造成存储级联关系时, 区分出值对象,可以考虑存储策略,因此可以提高程序性能(因为可能减少数据库的访问,减少缓存的压力):比如值对象可能不需要存储和保存(如规格类往往只是利用来进行验证或是计算的,一般不改,所以也就没有必要保存和更新),但也可能需要存储,是否存储由业务决定。
因此我的理解是:分析一个类是否作为值对象, 主要应该从以上方面考虑,而不应该以是否需要存储来作为和实体的本质区别。

同时由值对象是否需要存储而导致了值对象的不同创建策略,如果需要存储,说明这个值对象代表的规格是需要一再复用的,同时也是可以配置和修改的,创建采用读写文件形成,有需要的话可以结合反射技术。 如果不需要存储,说明是固化在代码中,对应的计算相对固定。

[该贴被boycott于2008-06-25 09:59修改过]

多谢boycott的总结,主要从设计角度谈了值对象几个特征,很有借鉴作用。

不错,分析得比较深入,学习中。。。

谈的非常之透彻

我的理解是这取决于具体的应用,如果这个领域只负责装配发动机,不需要区别哪个配件是哪个,这个配件就是值对象,如果领域需要维修发动机,并记录哪个配件发生过什么故障,做了哪些修理,反馈情况如何等等,这些配件显然就需要被记录,这时候就是实体。
按某类别分类,如果不允许一个东西同时拥有两个类别,按某个类别查询也要求查到的东西必须属于这个类别,就说明这些类别是需要被区分的,就是实体。

--我很赞同这们道友的观点,数据库表中的ID不应该作为区分实体与值对象的标识,我觉得!而是要看具体场景,有一些表在运用时既可以表现成值对象也可表现成实体!