SpeedVan认为的VO

VO,全称Value Object,中文名值对象。

我们平常说的Object一般是Reference Object,这是带有实体意味的。而VO相对于RO,有很大对立性。

1、没有所谓的唯一标识,若果真要说唯一标示,整个VO就是唯一标识。

2、VO有强烈的整体性,当一个VO被提出时,它一定代表着一种含义,且不能分割看待。

3、VO有着本质的不变性,这源自Value(值)的概念,VO是一种以Object存在的Value。这是与“变量集合”最核心的区别。

4、VO有着强烈的存在约束,基本就是一致性意思,这是这个存在约束决定该VO是否有效。


一、三项性质的体现:

例子:某图形对象:

graph{
edges = 3;

area = Area(5,cm2);
}

1、整体性:

获取面积时,不能如下表述:

num = graph.getArea().getNum();

unit = graph.getArea().getUnit();

println("面积为:"+num+unit);

应该如下:

area = graph.getArea();

println("面积为:"+area);//既然成为值,那么准备把toString也准备下吧。

2、不变性:

改变面积为原来2倍时,不能如下表述:

oldNum = graph.getArea().getNum();//破坏整体性

newNum = oldNum*2;

graph.getArea().setNum(newNum);//破坏不变性,值的本质严重破坏了

应该如下:

受语言限制,不能重载操作符:


{
oldNum = graph.getArea().getNum();

oldUnit = graph.getArea().getUnit();

newNum = oldNum*2;

newUnit = oldUnit;//这句为方便可以省略,这里是表达出本意。

newArea = new Area(newNum,newUnit);
}//大括号内的可以抽成一个函数
graph.setArea(newArea);

若果操作符更重载,则如下:

oldArea = graph.getArea();

newArea = oldArea*2;

graph.setArea(newArea);

3、存在约束:

newArea = new Area(-10,mc2);//在构造时,就调用检查函数,没效时,throw Exception,java一个比较麻烦的地方就是这里,new Area在异常时,不能让newArea获取“无效值”,来继续执行。也就是new Area失败时,newArea自动 = null,然后继续执行。js,scala这方面做得很舒服。有效体现在多个方面,一种是某值在有效域,一种是几个值符合某条约束,当然可能还有其他,这里就只是提点一下。

后注:因为java不是什么纯的OO语言,操作符不是针对对象,而是基本类型,有时回避这些问题,需要自己写函数解决。而写法还有更好的,这里先放上是我最初写法。

(这次快就说完是什么和怎么样了,下次就说为什么会这样,因为内容较多,需要整理一下)
待续,持续更新……

[该贴被SpeedVan于2011-08-05 11:42修改过]

二、性质的由来:

很多人把值对象认为其本质是一个变量集合,这是一种只看到其对象身份,而对其值身份盲目的观念。要想准确理解值对象,还得准确理解值。值(值对象)只有在其系统发生概念改变时,才能被改变,如“1元”变“2元”。值对象是以对象形式存在的值。

1、整体性(或原子性):

值的整体性,体现在其意义上,5cm2是Area类型的一个值,在谈论Area时,也就决定了最小单元是Area,既然5cm2已经是最小谈论对象(边界思维),也就不能拆分表示。破坏整体性等同破坏整个系统的概念,如在数字0~9,出现第11种数字。值对象是其系统最基本最原子的概念,不能被分割。

2、不变性:

最关键的性质,这个性质是继承自值的性质。每个值代表固定的概念,因为每个值是被定义的,被约束的。值与值之间是相互独立的,不是由谁变化得出谁,哪怕你看到9.9成是相同。111111与11111各自为值,不是谁变出谁,而是在该系统确立的瞬间,这些值就已经存在。在数字系统0~9中,是1是由0变来,还是其他呢?实数系统,字符串系统,一样的道理。
值本来就是被共享的:

获取偶数

list = {0,1,2,3,4,5,6,7,8,9}//请把这些当作值对象看待
res = {}//保存偶数结果
for(a <- list)
if(a%2==0) res.add(a);

//假若此处对2对象进行改变
2.set(3);//意为2对象改为3对象,注意这跟实体改变是两回事,实体改变是因事实而改变,而值对象不存在可被改变的事实理由。

print(res);

偶数结果是:0,3,4,6,8

可见,改变值对象,致使上下概念不一致,甚至导致逻辑崩溃。

3、存在约束:

值对象的有效性不应该在外界判断,而是应该存在即合法,不合理的值本身就不应该存在。

三、不变性


1、肉眼里的“1==1”
不考虑which、who,只考虑what,这的确是值对象的特点,值也一样。

在“1==1”中,我们看到“左边的1”和“右边的1”。因为值不会考虑which,所以无论是多少个“1”,无论这些“1”是什么时间什么空间,都是同一个概念(或定义,what)。所以对于值来说,无论有多少个,只要他们是同一个what,他们就相等。

2、值对象不是属性的划分。
认为是属性的划分是搞混了对象和类。

设某值类A


class A {
private String name;

public A(String name){
this.name = name;
}
//get自行补完
}

而值对象,是对象:


new A("123");

以上的是语言写法,我们可以用另外一种方式来表示:


new A{
name = "123";
}

从这里可以看出,值对象从实体划分出来的是“特征”,即name="123",而非属性name。

在一个值对象里,what是已确定,它不是待定的。what就是说new A里的各属性的值是什么。

what is new A("123")? An instance of class A, whose name is 123;

这点与不变性有什么关系呢?

既然划分的是特征,而不是属性,那么就不存在属性可变一说。

3、请记住你是为什么要值对象,你改的永远是变量,而不是值。

举例:


class Person {
private String name;

private String age;

```(代表其他属性,下同)

public A(String name, String age, ```){
this.name = name;
this.age = age;
```
}
//set、get自行补完
}

我们经过分析觉得name,age可以合并,作为某类Detail:


class Detail {
private String name;

private String age;

public A(String name, String age){
this.name = name;
this.age = age;
}
//get自行补完
}

于是Person变为:


class Person {
private Detail detail

```(代表其他属性,下同)

public A(Detail detail, ```){
this.detail = detail;
```
}
//set、get自行补完
}

好了,注意了!!!我们是在修改了Person的概念了,它没有name和age属性,只有detail属性,也就是说:改变后,不存在“改变Person的name”一说。也就是在我们语言中,只存在“修改某Person的detail”的说法,Detail是一个值类。某人名字变了,是指Person的detail变了,而不是Person的name变了。变了就重新赋值,所以我们只能重新对detail赋值,而不是修改detail所指的对象。