领域驱动设计-聚合根与实体定义和区别
2024年5月20日
在领域驱动设计(DDD)中,聚合根(Aggregate Root)和实体(Entity)都是领域模型中的重要概念,它们在模型中扮演不同的角色,具有不同的特点。
实体(Entity)
实体是具有唯一标识符的对象,它们可以拥有生命周期,并在系统中存在一段时间。实体可以是聚合的一部分,也可以独立存在。实体的属性可以随着时间改变,并且它们的身份是持久的。
特点:
- 唯一性:每个实体都有一个唯一标识符。
- 生命周期:实体可以被创建、修改和删除。
- 持久性:实体的身份和状态在系统中是持久的。
聚合根(Aggregate Root)
聚合根是一组相关对象的集合,这些对象共同形成一个“聚合”。聚合根是聚合的入口点,它定义了聚合的边界,并且控制对聚合内部对象的访问。聚合根本身也是一个实体,但它还承担了额外的责任,如维护聚合的一致性和完整性。
特点:
- 一致性:聚合根负责确保在聚合内部的所有对象状态的一致性。
- 边界:聚合根定义了聚合的边界,外部对象只能通过聚合根与聚合内部的对象交互。
- 入口点:聚合根是外部世界与聚合内部对象交互的唯一入口。
- 实体:聚合根本身是一个实体,但它还承担了聚合的责任。
区别
- 角色:实体是领域模型中的普通对象,而聚合根是具有特定责任的实体,如维护一致性和定义边界。
- 一致性:聚合根负责维护聚合内对象的一致性,而实体本身不承担这一责任。
- 访问控制:聚合根控制对聚合内部对象的访问,外部对象不能直接访问聚合内部的对象。
- 边界:聚合根定义了聚合的边界,而实体没有这一概念。
- 生命周期:虽然聚合根本身是一个实体,具有生命周期,但它的生命周期管理通常与聚合内其他对象的生命周期紧密相关。
示例
假设我们有一个电子商务系统,其中包含订单(Order)和订单项(OrderItem)。
- 订单(Order):可以作为聚合根,因为它定义了订单的边界,控制对订单项的访问,并维护订单的一致性。
- 订单项(OrderItem):是聚合的一部分,但它本身不是聚合根,它依赖于订单聚合根来维护其生命周期和一致性。
在代码实现中,聚合根可能会包含对内部对象的引用,并提供方法来管理这些对象,同时确保整个聚合的一致性。
public class Order : AggregateRoot
{
private List<OrderItem> orderItems = new List<OrderItem>();
public void AddOrderItem(Product product, int quantity, decimal price)
{
var orderItem = new OrderItem(product, quantity, price);
orderItems.Add(orderItem);
// 这里可以添加额外的逻辑来维护订单的一致性
}
// 其他方法...
}
public class OrderItem
{
public Product Product { get; private set; }
public int Quantity { get; private set; }
public decimal Price { get; private set; }
public OrderItem(Product product, int quantity, decimal price)
{
Product = product;
Quantity = quantity;
Price = price;
}
// OrderItem 不是聚合根,因此没有管理聚合的责任
}
在这个示例中,Order
类是聚合根,它管理 OrderItem
对象的集合,并提供添加订单项的方法。OrderItem
类是一个实体,但它不是聚合根,它依赖于 Order
聚合根来维护其生命周期和一致性。