变与不变源自对于VO理解的不同。
如果把它只作为一个数据的载体,纯粹的载体就像DB中的一行记录,那么它就是可以改变的,因为除了数据本身它没有意义。
如果把它作为对象级别看待,那么不应该有改变,如果改了就不再是同一个对象了也就是被替换了。比如电脑上的一个页面,它属于自己的应用程序。

2011年06月07日 16:14 "@IceQi"的内容
变与不变源自对于VO理解的不同。
如果把它只作为一个数据的载体,纯粹的载体就像DB中的一行记录,那么它就是可以改变的,因为除了数据本身它没有意义。
如果把它作为对象级别看待,那么不应该有改变,如果改了就不再是同一个对象了也就是被替换了。 ...

不错的见解,我可能会“极端”一点,按照同样的内容,我的理解是:DB中的一行记录是实体,而不是值或值对象,标识是行号,字段是每行(实体)的变量名,而其中的内容就是值了。从中我们不难发现,我们脑子中是想着“XX行XX字段的内容改为XXX”,可见要想发生改变就需要找对对象,试想若果没有“XX行”,更改行为从何谈起?被改的对象是“实体”,改变的是“变量”,内容则是“值或值对象”了。

我个人觉得,值对象本身概念是不可变的,出现可变的,是因为妥协,但使用前提是:
1、不需共享;(当然可以硬用,但需要锁来解决共享问题,也就是说可变值对象本身不能解决共享)
2、求效率;
3、内存紧张等。

个人认为,这种妥协产生的是一种变异的值对象,当然我不否认其存在,只是一旦使用了,就不要说这就是值对象。

对于理解的人是一种妥协。对于不理解的人则是原则问题了。

软件设计没有绝对,但凡不外乎平衡。VO的本质是对象,而可改变的则不能称为对象了,它只是数据集合。这里的问题就是如何在VO和数据集间做出平衡的选择。

当下对于对象的理解至少我周围还未见几个人,但是VO的概念已经被很多人接受很多年了。在没有真正理解对象的时候VO既是一个内存实例,其中有很多项数据,仅此而已。这是很多人的出发点。

可以更多的从对象的角度出发再深层一些思考,VO和数据集合间的区别。
[该贴被IceQi于2011-06-07 21:55修改过]

2011年06月07日 16:53 "@IceQi"的内容
而可改变的则不能称为对象了 ...

为什么?

2011年06月07日 16:53 "@IceQi"的内容
可改变的则不能称为对象了 ...

我也想问为什么?这明显与我观点不同。

我说值对象不可变,是源自值的概念,值对象只是代表值的对象而已。值对象是表达值的边界,是把一组相关的值(也可能是一个)组装成为一个整体。值不可变,组装出来的值(值对象)也是不可变的。

一个值是一组概念(或者定义),若果值可变,则一个值代表多组概念(或者定义),这明显是不对的。(1能代表1的同时,也能代表2不?)

数据集与值对象明显不同,也不同于实体,数据集,是一个集合,也没有规定可变不可变,如同set。

而我们平时用的“可变值对象”(我已经很少用了),只是单纯对“变量”的划分而已,没有从“值”方面考虑(整体性,不可改变性)。这种划分,与原来作为上级对象的变量,没有根本的区别。

我的意思是如果作为对象来看待,那么其中的关键值是不能从外面修改的(setInt),如果从外面进行了修改那么通常被描述地对象也已经变化了。比如一张订单,如果定货的数字被更新了,那么我更倾向于在软件模型上把它作为一个新的订单对象来处理。

我上面的说法的确有问题。

另外值对象,我不喜欢这个说法。对象地核心应该是“对象”而不是“值”,这个听起来很忐忑,但是如果一个对象里面只有值并且是核心,那么他和单纯地数据集合有什么区别?数据集合显然不是对象。

是的,值对象也可以有方法,而不光是只有“值”。最起码,值对象可以包含数据的有效性验证方法。当然,业务方法这个也可以有。

2011年06月20日 10:36 "@IceQi"的内容
对象地核心应该是“对象”而不是“值”,这个听起来很忐忑,但是如果一个对象里面只有值并且是核心,那么他和单纯地数据集合有什么区别?数据集合显然不是对象。 ...


对象是一切的基础,值对象只是对所有对象的划分而已,就好像“白米”,“黑米”,“红米”,米仍然是本体,但是是带有白,黑,红的概念和定义。对象只不过是边界,是什么样的边界,就需要用“值”,“实体”来进行定义。当我们的问题是“黑米能吃不”时,米本身就公认能吃,米也就不是问题的主体了,而是对这种颜色的怀疑,和能不能吃的问题。

可能这例子有点不好,以下再列个:
//content
三聚氰胺的奶粉(值的对象,值对象),奶粉是被关注的对象,是问题的基础。对奶粉划出“三聚氰胺的奶粉”,奶粉则是基础环境,但已经不是问题的主体,现在是对“三聚氰胺”的关注,这个对人体如何。有毒,没毒?(可变,不可变?)

2011年06月20日 21:55 "@showerxp"的内容
值对象可以包含数据的有效性验证方法。当然,业务方法这个也可以有。 ...

值对象可包含验证方法,从值的角度说,这并没有问题,因为验证并没有破坏值的整体性和不可改变性,而且从对象角度说,这方式可体现内聚性。但业务方法,放在值对象就不敢认同了。值对象是一组概念,是被实体(中的变量)所拥有,而业务方法应该跟随实体,或者与实体直接相关,而不是从值对象上面获取。当发现业务方法难以放入任何现存的实体时,并且该方法不能独立存在时,就需要考虑模型的错误或者缺失(这正是DDD深入领域发现实体,发现对象的过程)。

[该贴被SpeedVan于2011-06-21 09:06修改过]

忽然想到点东西,对象是依赖于业务环境的,同一个内存块在业务A中是对象,在业务B中只是数据。

String,在只关注到他描述的“字符串”的环境中他算不上对象,这时候他和char[]没什么区别;转换到一个需要他subString\find\compare的环境中他就是对象了。

感觉我们思想上没有太大的区别,貌似你说的“白米”只是在“米”上增加了“白”就成了描述“白米”的值对象。不过我还是不喜欢“值对象”这个名字。

2011年06月02日 16:34 "@SpeedVan"的内容
In my opinion,把第二种方法所有变量都用一个带set的VO封装起来的话,就与第一种同理了。 ...

翻来翻去又看到这里了。

我说不喜欢“VO”这个名字是因为他貌似强调值而忽视对象本身了,对很多人有误导之嫌。比如你一句“所有变量都用一个带set的VO封装起来”,到很多人的脑袋里就变成贫血模型了,对象本身被彻底忘记了。

做软件更多的时候是在权衡,权衡的基础是理解所有选项的长短,比如即使你使用了set也未见得会出来一个贫血模型,又或者你用了贫血模型但是却理解这不是一个完整的对象。

我也会倾向第二种方式,有一些时候一个纯粹的数据集合是很方便和高效的方式。对于这种情况可以更纯粹一点弄个public String vo;不是更方便么。

从obj.vo ---> obj.set(get)Vo ---> obj.setVo(写)/obj.vo(读) ---> obj.vo(我现在的选择之一),一路走来好多年承载了很多软件思想的变化。

2011年06月22日 14:43 "@IceQi"的内容
我说不喜欢“VO”这个名字是因为他貌似强调值而忽视对象本身了,对很多人有误导之嫌。比如你一句“所有变量都用一个带set的VO封装起来”,到很多人的脑袋里就变成贫血模型了,对象本身被彻底忘记了。

做软件更多的时候是在权衡,权衡的基础是理 ...


VO没有忽视对象,而是在肯定了对象基础上进行划分而已,是值的概念引来了一种特殊的对象。贫血模型也是对象,他是一个数据载体,或者说是一个变量集合,但他不是实体对象,也不是值对象。对象讲究的是边界,实体讲究的是唯一标识,值对象讲究整体性,唯一性,不可改变性。

>>obj.vo ---> obj.set(get)Vo ---> obj.setVo(写)/obj.vo(读) ---> obj.vo
<<这与我所说的值对象不可变无关,obj如何set、get与值对象变不变没有任何关系。我的意思是vo.setValue1(x)不应使用,从本身概念也不应该存在。obj.vo.setValue1(x)这是违背值对象的做法。从而失去“关注实体离散状态”的效果。


关于讨厌VO这个名词,我的讨厌方向跟你不一样,在谈论实体时,我更喜欢用“实体状态”(entity state),我认为值对象是entity state落地的一种方式,因为entity state必须是整体,离散关注的,所以值对象适合担当这任务。

Contract对象
|-- id属性
|-- customerid属性

status VO
|-- createRequstConfirm
|-- createRequstConfirmDate
|-- downPaid
|-- downPaidDate
|-- marginPaid
|-- marginPaidDate

balance VO
|-- totalLoanAmount
|-- totalTimes
|-- totalIntrestAmount
|-- paidLoanAmount
|-- paidIntrestAmount


实际的例子:contract对象持有两个VO,status和balance,我不觉得修改status和balance的值对造成什么概念上的麻烦,难道因为付款后需要更新paidLoanAmount和paidIntrestAmount就需要整个替换balance么???
[该贴被pye于2011-06-28 11:32修改过]
[该贴被pye于2011-06-30 13:11修改过]

2011年06月28日 11:29 "@pye"的内容
难道因为付款后需要更新paidLoanAmount和paidIntrestAmount就需要整个替换balance么??? ...

呃,现在才看到,不好意思,不过下次记得引用一下,让我收到回复提示。

关于你说的整个替换,是的。哪怕只是改变了一丁点,也是整体替换,这是因为你把他们看作整体的原因。balance的提出就是一组概念(是一组,不是零散的),他不是实体,并不持有状态。若果你觉得balance真的存在独立变化的东西,那么需要考虑边界是否存在问题。

其实“实体状态”(即落地为值对象),在自然界也可以找到类似的道理:
我和你看到一个青色的香蕉,这里有“我看到香蕉的[青色]”和“你看到香蕉的[青色]”。一段时间后,香蕉变黄了,你看到一个黄色的香蕉。于是,你得到“你看到香蕉的[黄色]”。但我没看到,所以我依然是得到“我看到香蕉的[青色]”。

从这段话中可以知道,[青色][黄色]就是状态(值),是对应颜色变量。我们都是获得这样的一个状态(值),无论香蕉怎么变,你也不会认为“[青色]从概念上变成了[黄色],才会认为香蕉变[黄色]”,你可参考枚举。

青色(红x1,黄y1,蓝z1)
黄色(红x2,黄y2,蓝z2)

(对值对象正确的理解)颜色=青色->颜色=黄色
(对值对象错误的理解)颜色=青色->颜色=青色.set(红x2,黄y2,蓝z2)


实体状态(值对象),是由多个值组成,而值对象,只能由值组成,即是全体不可变的,所以值对象从本质上也是不可变的。既然你认为它是balance,那么它就是一整个balance概念,而不是里面某一个。修改balance,就是重新赋给他一个新值,而不是去修改旧值的概念。

而正因为这种修改旧值的处理方式,不能对应现实,同时又想实现现实的共享,才会引发共享问题。

一切状态本来就存在这个世界上,只是我们还没有发现而已。

我觉得VO不变是指不能质变,如果是量变,还是可以的。
比如一个入库单是某个原材料的VO,那么这个入库单在成为原料的VO后,又增加了经办人、经办时间等属性。那么这只能看做对入库单的完善,入库单本质上还是入库单。
如果指向入库单的目的是为了记录该入库单在指向当时的状态,那么就要复制了。因为指向对象与指向对象的状态是两个概念。

2011年07月08日 10:25 "@redorange"的内容
我觉得VO不变是指不能质变,如果是量变,还是可以的。
比如一个入库单是某个原材料的VO,那么这个入库单在成为原料的VO后,又增加了经办人、经办时间等属性。那么这只能看做对入库单的完善,入库单本质上还是入库单。
如果指向入库单的目的是为了 ...

真可谓“名可名,非常名”。可能过去人们为方便使得VO可变,得益不少,但到了并发年代,却处处受挫。

首先,我还是得提出一个新概念“(值)变量集合”,这就是过去所谓的VO。但这种方式没有注意到,这从根本上已经歪曲了Object的定义,我重申 Object不是Class,Object是考虑变量的值,Class是考虑变量。“入库单还是入库单”,这只是指类还是那个类而已,并不是对象还是那个对象。“Bill还是Bill”,但不是“new Bill()还是new Bill()”。

(之前说法有点偏,现重写:)
注意,下面的前提:Bill是值对象,不是实体。
我们重新来看“Bill可变”,明显地此时的Bill并不是值对象,而是“变量集合”(经思考,这还不是类)。用“象”表示可能更清楚:
此时的Bill是这样:

new Bill() {//过去的VO,这样写是为了表达这时候的VO,只关注经办人和经办时间这两个变量。
经办人(变量)
经办时间(变量)
}

这是以一个对象的方式,存放着多个变量,但不是把这个对象看成值。

而“new Bill()不可变”,“象”如下:
//以下方式是只关注值经办人1、经办时间1等,与上者明显不同。
new Bill(经办人1,经办时间1);
new Bill(经办人2,经办时间2);

再回国头来说增加经办人信息等:
new Bill(null,null);//注意Bill不是实体,上层实体的变量entity.bill=new Bill(null,null);
new Bill(经办人1,经办时间2);//entity.bill = new Bill(经办人1,经办时间2);

可变的做法是:
entity.bill.经办人 = 经办人2;
entity.bill.经办时间 = 经办时间2;

(以下还有补充,待续)

好了,bill不是实体,而是entity的一个状态变量,所以我们获得entity的状态的时候就是一个bill的值,不是值中值。bill不是状态,而是new Bill()才是状态。

当我们说“可变”的时候,请认真想清楚,到底是在说对象上面的属性可变,还是在说值对象。

若果还是反对,还是迷惑,请抛开历史,重新思考,问自己一句:到底是谁在变?

[该贴被SpeedVan于2011-07-08 12:44修改过]
[该贴被SpeedVan于2011-07-08 14:15修改过]