关于ForumState为值对象的疑惑

banq大哥你好!你说ForumThreadState是值对象,但是:

1.“值对象是不可变的,不要给它任何标识,避免实体的维护性,降低设计复杂性。我们不关心值对象是哪个实例。”,好像ForumThreadState是可变的,有set方法,而且每次回复后,都会重新去数据库统计一下。不过再细看代码,在refreshState的时候是new了一个ForumThreadState,就是说重新生成了新的ForumThreadState。ForumThreadState好像在性能方面也没发现有什么优点,不具备值对象的特点。

2.每次都要根据forumThread才能确定ForumThreadState,所以我们要关心ForumThreadState是哪个forumThread的对象,这跟DDD里面说的“只关心它们是什么,而不关心它们谁是谁的对象”相违背。

3.假如ForumThreadState是值对象,具有不变性,那应该可以共享啊,但是每个forumThread
实体的ForumThreadState都不同的,不能共享,矛盾。

4.不清楚把ForumThreadState设计成值对象的好处在哪里。

上面问题我一直很迷惑,对值对象的概念没完全理解,网上找了相关文章,有举了货币转换的例子,看了懂了,但一回到ForumThreadState,又迷惑了,请banq老师指导,谢谢!!

banq在某个帖子中提到的:Form由ForumState组成,ForumState是经常更新的,所以我们设计为一个状态值对象,如果不设计这个值对象,ForumState中的字段都放在Forum中,那么更新这些字段会导致Forum这个大对象锁住,从事务性能等方面都是不好的,从Evans DDD的OO设计角度也是不对的。

状态值对象和DDD中的定义的共享不可修改值对象我觉得有大大的区别,自己感觉在jivejdon中没有真正体现DDD的值对象概念,顶一下这个帖子,望banq及时解答!

如果值经常被改变,是允许值对象的值被改变的。一般来讲如果使用了不同的属性值,是要重新生成整个值对象而不是修改某个已存在的值对象的属性,但是state的更新过于频繁,生成它需要查询并构造状态,代价也算高了,值对象似乎没有起到共享作用,是一次性的。
state或者在更新时付出代价更新这些值,或者在查询时付出代价来重新查询。

假设将论坛标题、URL、menu等做成值对象,就可以达到共享作用,并在修改它们时通知加载器重新载入。但这种修改并不频繁,维护一个实例就可以。

值对象最关键定义是表明对象的特征(这应该DDD书籍值对象章节第一句话),那么状态是不是对象的特征呢?我认为应该是,只不过这个特征随时更改,难道经常更改的东东就不是特征吗?所以,从这个角度我将ForumState化为值对象,有时我发现,也许可以将将ForumState和FourmThreadState这两个合并为一个值对象State,这样可能更体现值对象的共享特性。

值对象更多有时表现为一种description描述,特征描述,这就是四色图中的description,这是最标准的值对象,值对象是否可更改,完全由设计者决定,而不是说不可变的才是值对象。

[该贴被banq于2008-05-21 14:23修改过]

我又仔细想了想,如果笼统地说状态属于特征还有些值得商榷,状态最多只能算动态特征,而特征我们通常指天然静态特征。这个问题留待讨论。

DDD中也说:如果我们只关心模型中一个元素的属性,那么就可以把这个元素划为值对象,按照这个定义,最新帖子应该Forum和ForumThread等对象中很重要的一个元素,我为了表示其整体一致性,一旦有新帖,Forum或ForumThread的State就必须全部更换。这些都是吻合的。

DDD文章大部分是在讲静止的特征,比如两个人的名字,名字就是值对象,可以在两个人实例中共享,这些都容易理解,但是我个人觉得这只是DDD在解释值对象,它没有解释到的就不代表不是值对象,就象ForumState一样,甚至与它具体解释矛盾的地方。

无论如何,也许只有等Evans本人才澄清才会圆满,但是作为一种客观的方法论,如果依赖本人的不断解释和说明,那么本身是有问题的,我们不希望Evans本人来说明;也可能我们过于钻牛角尖了,OO世界非常广阔,不可能一个流派DDD能包打天下,分析模式 设计模式等其他都可以作为参考,我们只要掌握DDD精神,特别是其将值对象或子对象约束于根对象的约束性;这些比毫无业务层次的平面数据表要进步多,使得我们访问一个数据必须获得其宿主,而不是无知无畏不顾业务场景地直接访问数据表,这些都能减少BUG,带来程序健壮性。

当然DDD不只是这些优点,还有待每个人去体会,DDD指明了一个可实现的方向,但没有涵盖所有实现范畴,这是我们使用DDD特别要注意的。以上只是个人观点。

我认为state在初次创建时load一次属性即可,以后每当发帖就通知它,用新帖的属性去更新state里面的值,不必每次都重新查询。信任内存。

一个是主动通知,一个被动刷新,我先考虑比较一下他们区别和特点,谢谢,

其实这两种情况本质上都是一样的,只是通知方式需要维护一个内存数据库Map,但是既然都是取得对象,仓储也没规定必须从物理DB获得,Forum并不多,state的数量是有限的,这个内存Map不会扩张。就像许多固定状态码(比如省份代码)在初始时加载就可以,为了保证它在修改时同步,就加入通知事件,其实也相当于更新了物理DB中的state,但是并不需要实际更新,因为下次重建时还是会从物理DB加载最新状态,而此前的状态是由内存维护的。区别在于固定状态码的更新频率很低,基本固定不变,而ForumState更新频繁,但DDD说明了一点就是对值变化频繁的值对象是允许更改它的属性的,特别是创建这种对象代价比较高的时候。我认为创建一个可用的state代价就比较高了。