DDD 把领域对象分成了两种:一种是实体,另一种是值对象。
值对象则往往是用来描述实体的属性“值”的。
DDD 强调实体和值对象的区别,可以让领域建模更加准确和深入。
值对象的概念
判断同一性的问题,就是如何确定“一个对象就是这个对象自身”的问题。
实体是靠独立于其他属性的标识来确定“同一性”的。
在 DDD 里,像员工这样有单独的标识(员工号),理论上可以改变的对象,就叫做实体(Entiy);像员工状态和时间段这样没有单独的标识,并且不可改变的对象,就叫值对象(Value Object)。
实体和值对象的差别
实体是一个“东西”,而值对象是一个“值”,往往用来描述一个实体的属性。
值对象的优点
- 主要体现在内存和数据库布局的灵活性上
- 值对象的不变性可以带来更高的程序质量
值对象的内存布局
对于实体来说,共享是对的,不共享就不对了;而对于值对象来说,共享和不共享,都对。这是为什么呢?
这是因为,值对象是不可修改的。所以,即使在内存里重复出现了,也不会像实体那样,由于修改而导致错误。
要实现对象的共享,其实需要更复杂的编程,所以,值对象在内存里多数是不共享的。
什么时候应该共享值对象呢?当值对象的体积比较大,数量比较多,共享值对象可以节省大量内存的时候,就可以采用共享的方式。这种用法实际上是一种设计模式,叫做“享元”,也就是共享的单元,英文是 Flytweight。
值对象的数据库布局
“嵌入”到所属实体表的方式,是值对象最常见的存储方式
在数据库里是同一个表,在内存里却是不同的对象,这种数据库和内存的差异,称为阻抗不匹配。阻抗不匹配有多种形式,对象的嵌入式存储只是其中一种。在程序里进行数据存取的时候,就要进行转换,来消除这种不匹配。这种转换工作,是在仓库,也就是 Repository 中完成的。其实,消除这种阻抗不匹配,正是像 Hibernate 这样的 ORM 框架的主要目的之一。
不变性在数据库操作的体现
假如李四搬走了,换了地址,那么应该把和他相关的地址记录删除,再插入一条新地址,而不是改变地址表里原来的记录。