关于值对象及相关概念的梳理

来源:互联网 发布:redis做数据库 编辑:程序博客网 时间:2024/05/22 03:11

值对象VO,顾名思义,也就是代表着值的对象,它通常是被当做一个值来使用。

回想一下,在经典的算法编程里面,值是如何使用的?

int count(int x,int y){

return x+y;

}

就像这样的变量x y,使用某个值,也就是传一个数值,它不具有状态,生命周期,仅仅给更高层的单位提供数据。值对象就是将上述的变量x y提升到了对象级别,可以提供一组数据。从更高的角度来讲,值对象具有更多特性。

不变性

例如上述的x,如果传入的是5,那这个值就是5,如果传入变成6,那么这个值就是6,也就是不再是同一个值。在一个购书业务用例中,所购买的书的价格、折扣、打税这三个属性我们就可以聚合为一个值对象:售价。如果里面的某一项属性变了,那么售价就变了,也就不能认为是同一个价格。这一约束具体是通过编程语言提供的机制来限制它的二次修改。

不能有行为

如果一个值对象具有某种行为,那么就意味着它提供的值或内容是量变的,也就违背了不变性。这个跟不能有状态是一个意思。


为了更全面的说明,这里引入实体对象来进行比较。

实体对象Entity,代表现实中一个确定的唯一的个体,是某一个人或某一本书的映射。每一个实体对象在数据库中都由唯一的ID对应和区分,但是不在乎它们的属性值是否相同。例如两本一模一样的书,但是对应的就是两个实体对象。这点在值对象身上是不可能发生的。

实体对象有状态和生命周期,例如在借书用例里面,某一本书会被借走、归还或剔除,当移除这本书的时候,它对应的实体对象也会被修改属性然后持久化,或者从持久化中抹去。但是值对象不具有这样的关联操作,需要的时候就可以直接使用,不需要的时候就可以直接抛弃,不会对以外的东西造成任何影响。如上述的不变性中的售价,在买书的用例中,业务只关心顾客付款是否足额,而不关心具体卖了哪本书,因此提供一个售价作为依据即可,这个售价没有必要在这个用例里面持久化或修改状态,因此售价就是一个值对象。


值对象的用途

1、封装一些零散的、关系不大的、不构成整体的数据组合。

2、用在领域驱动设计DDD的领域层。可以把实体对象中的一些属性剥离出来,封装在一个值对象中,然后内聚在实体对象中,从而使这些属性可以脱离实体对象的状态来使用,也就是属性跟实体解耦了。例如上述的买书的用例,售价原本是书的一部分属性,我们将它放入值对象,而账单中只需要用到金额这部分信息,因此我们只需将此值对象交给账单使用,无须把整个书实体对象拿过来,从而大大提高效率。更重要的一点是,由于实体对象是有状态的,它的售价也许在业务执行过程中或其他时间发生改变(例如被其他业务操作修改),但是账单中应该记录的是书卖出时的售价,如果账单直接跟实体关联,那么就会受到实体状态的污染发生错账,这点在并发操作时尤为重要。所以,账单中也需要保存一份当时的售价,这个时候值对象就发挥解耦的作用了,由于它具有不变性,不会随着实体的状态而发生改变,可以安全放心的提交给账单,甚至可以复用为账单的属性。


注意事项

1、实际使用中要考虑到弱不变性和强不变性。

2、要根据具体业务来区分值对象,例如书的售价在买书用例中可以作为值对象,但是在借书用例里面就不能作为值对象。

3、值对象通常都是实体对象的一个属性,因此是依附于实体对象进行持久化的,不能单独进行持久化。如果是字典类型的,则可以考虑持久化。


阅读全文
0 0