了解 DDD 中实体和值对象的定义和区别,学习如何在你的领域模型中应用它们来建模复杂业务逻辑。
chou403
/ DDD
/ c:
/ u:
/ 6 min read
一学一个不吱声
在领域驱动设计(DDD,Domain-Driven Design)中,实体(Entity)和值对象(Value Object)是两个重要的概念,它们用于描述系统中的对象及其行为。
实体(Entity)
实体是具有唯一标识的对象,它们在系统中具有独立的生命周期。实体的身份(ID)在整个系统中是唯一的,并且它的属性可能会发生变化,但其身份不会改变。
特点:
- 唯一标识: 每个实体都有一个唯一标识符,用于区分不同的实体实例。
- 独立生命周期: 实体具有独立的生命周期,可以单独存在并且会随着时间发生变化。
- 可变性: 实体的状态和属性可以随时间发生变化。
例子: 在一个电子商务系统中,用户(User)是一个实体,因为每个用户都有一个唯一的用户ID,并且用户的属性(例如名字,电子邮件地址)可能会随时间变化。
public class User {
private String userId;
private String name;
private String email;
// 构造函数,getters,setters
}
值对象(Value Object)
值对象是没有唯一标识的对象,它们是通过属性来描述的。值对象是不可变的,即一旦创建,其状态就不能改变。值对象通常用于描述某种特定的属性或概念。
特点:
- 无唯一标识: 值对象没有唯一标识,它们通过属性值来判断是否相等。
- 不可变性: 值对象一旦创建,其属性值就不能改变。如果需要改变值对象的属性,通常是创建一个新的值对象。
- 用来描述特定概念: 值对象通常用于描述某个具体的概念或属性,而不需要单独存在。
例子: 在一个电子商务系统中,地址(Address)可以是一个值对象,因为地址只是描述一个具体的地点,并且它的属性(如街道,城市,邮政编码)一旦确定就不会改变。
public class Address {
private String street;
private String city;
private String postalCode;
// 构造函数,getters
}
实体与值对象的比较
- 身份: 实体有唯一标识,而值对象没有。
- 生命周期: 实体有独立的生命周期,而值对象通常与其所在的上下文一起存在。
- 可变性: 实体是可变的,而值对象是不可变的。
通过区分实体和值对象,DDD帮助我们更好地建模领域,确保系统中的对象能够正确反映业务需求并且易于维护和扩展。
举例说明实体和值对象
假设我们正在设计一个电商系统,需要设计一个订单类。订单包含多个订单项,每个订单项对应着购买了某个商品的数量和价格。
首先,我们定义一个订单项类,它包含订单号,商品名称,数量和单价4个属性,并且它们都是可变的,因为每个订单项都可以修改:
public class OrderItem {
private String productName;
private int quantity;
private BigDecimal unitPrice;
privatr String orderNo;
//setter 和 getter
}
然后,我们定义一个订单类,它包含订单号,订单项列表,订单状态和订单总价四个属性。
public class Order {
private long orderId; // 实体
private List<OrderItem> orderItems; // 值对象zh
private OrderStatus status;
private BigDecimal totalPrice;
}
我们在数据库中存储订单的时候,可以这样存储:
orderId | status | totalPrice | orderItems |
---|---|---|---|
2023021811223344 | CONFIRMED | 120 | {"productName":"《深入理解Java核心技术》 作者 Hollis","quantity":100,"unitPrice":129} |
以上,订单就是一个实体,因为每一个订单对应一个单独的数据库记录,并且有唯一表示,就是订单号。而订单条目就是值对象,他是依赖于实体进行存储的。
在数据库中把数据取出来的时候,是可以把orderItems这个json类型的字段转成我们定义好的OrderItem的对象的。这样更方便我们进行操作。