
这将会是一个长系列,从 DDD 的基础划分,到 CQRS 、Specification 的实践落地以及实践驱动等。
前言
值对象是实体的一个重要组成部分,如何正确使用值对象,也是 DDD领域驱动设计的一个难题。本文将介绍值对象的概念与使用方法。
概念
- 值对象是实体对象的属性,通常代表分量、性质、关系、场所、时间或位置/姿态。当实体属性需要表现出其属性的意义,并为这个意义提供相关功能,可以设置为值对象。比如一家公司所在的省/市/区/街道可以合成值对象表示这家公司的地址属性。
特点
- 值对象不可变。建模优先考虑值对象,因为值对象没有身份表示的负担,本身不可变。值对象本身最多是不可变性。
- 值对象拥有的往往是“自给自足的领域行为”。这些领域行为能够让值对象的表现能力变得更加丰富,更加智能。
领域行为
那什么是值对象的领域行为呢?
- 自我验证:值对象自我组合,能减少实体类的验证
- 自我组合: 值对象会涉及对数据值的运算,为了增强值对象的运算能力,可以在内部进行数据组合。如 金额的单位换算。
- 自我运算: 按照业务规则对属性值运算的行为。如经纬度计算。
// NewCoordinateVo 初始化坐标值对象
func NewCoordinateVo(LongitudeStr string, LatitudeStr string) (*VoCoordinate, error) {
// 自我验证
Longitude, err := strconv.ParseFloat(LongitudeStr, 64)
if err != nil {
return nil, fmt.Errorf("Longitude_input_err")
}
Latitude, err := strconv.ParseFloat(LatitudeStr, 64)
if err != nil {
return nil, fmt.Errorf("Latitude_input_err")
}
return &VoCoordinate{
Longitude: Longitude,
Latitude: Latitude,
}, nil
}
F&Q
- 相比于普通属性,值对象有哪些优势呢?
- 可以展现领域概念;学生实体的年龄,string与Name、int与Age相比,显然后者更加直观得体现了业务含义。
- 可以封装显而易见的领域概念;比如对于一个经销商4s店店位置经度和纬度都是这个4s店实体实体店属性,但是合成一个坐标值对象更能展示实体店领域概念。
- 更好的封装利于自我领域行为的验证能力。保证每次生成得值对象都是正确的。
2. 那么一个领域的概念我们用实体还是值对象呢?可以依据几点来判断?
- 业务对它相等的判断是根据值还是身份标识。前者是值对象,后者是实体。当我们从图书馆判断一本书是否相同,即使名字相同也并非同一本书,在系统中,只有id相同才是同一本书;但我们判断一个位置,当经纬度相同的时候就是同一个位置。这个时候图书就是定义为实体,坐标定义为值对象。
- 确定对象的属性值是否会发生变化,如果变化了,究竟是产生一个完全不同的对象,还是维持相同的身份标识。在员工的出勤记录业务场景中,依据相等性进行判断时,可以任务出勤记录值相等的就是同一条记录,但如果员工提出补卡,对记录状态修改对时候,其同一性就只能通过唯一的身份标识进行判断,这意味这应该被定义为实体。
- 生命周期是手动的。值对象没有身份标识,意味着无需管理其生命周期。但是实体无需关注。
多个判断条件是层层递进的,要确定一个领域概念究竟是实体还是值对象,需要谨慎判断,综合考量。
作者:于欢
来源:微信公众号:行创技术分享
出处:https://mp.weixin.qq.com/s/nZQh4pbkC_hut8FuQECTXQ
创业项目群,学习操作 18个小项目,添加 微信:923199819 备注:小项目!
本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 zoodoho@qq.com举报,一经查实,本站将立刻删除。
如若转载,请注明出处:https://www.zodoho.com/91362.html
如若转载,请注明出处:https://www.zodoho.com/91362.html