在领域驱动设计(DDD, Domain-Driven Design)中,聚合根(Aggregate Root)是一个重要的概念。聚合根是一个聚合(Aggregate)的入口点和控制者,负责维护聚合内部的一致性和不变性。
聚合(Aggregate)
聚合是一个或多个相关对象的集合,这些对象通过一定的业务规则绑定在一起,并被视为一个单元。聚合内部的对象通过聚合根进行管理。
聚合根的定义和职责
-
聚合根(Aggregate Root):
- 聚合根是聚合的入口点和唯一标识,外部系统只能通过聚合根来访问聚合内部的其他对象。
- 聚合根保证了聚合内部的所有不变性条件(Invariants)和业务规则。
- 只有聚合根可以直接保存到数据库,其他对象通常作为其组成部分被间接持久化。
-
职责:
- 维护不变性:聚合根负责确保聚合内所有对象的一致性和不变性条件不被破坏。
- 管理生命周期:聚合根负责管理其内部对象的创建、修改和删除。
- 处理业务逻辑:聚合根负责处理与聚合相关的业务逻辑和操作,外部系统通过调用聚合根的方法来执行这些操作。
聚合根示例
这里是使用C#代码来说明聚合根的几个特点的例子。我们以购物车(ShoppingCart)和购物车项(CartItem)的聚合作为示例展示聚合根的特点。
唯一入口
唯一入口意味着外部系统只能通过聚合根来访问和操作聚合内部的对象。
public class CartItem
{
public int ProductId { get; }
public int Quantity { get; }
public decimal Price { get; }
public CartItem(int productId, int quantity, decimal price)
{
ProductId = productId;
Quantity = quantity;
Price = price;
}
}
public class ShoppingCart
{
public int CartId { get; }
public int CustomerId { get; }
private List<CartItem> Items { get; }
public ShoppingCart(int cartId, int customerId)
{
CartId = cartId;
CustomerId = customerId;
Items = new List<CartItem>();
}
public void AddItem(int productId, int quantity, decimal price)
{
// 业务逻辑和不变性检查
var item = new CartItem(productId, quantity, price);
Items.Add(item);
}
public void RemoveItem(int productId)
{
// 业务逻辑和不变性检查
Items.RemoveAll(item => item.ProductId == productId);
}
public decimal CalculateTotal()
{
return Items.Sum(item => item.Quantity * item.Price);
}
public IReadOnlyList<CartItem> GetItems() => Items.AsReadOnly();
}
// 使用示例
var cart = new ShoppingCart(1, 1001);
cart.AddItem(2001, 2, 10.0m);
cart.AddItem(2002, 1, 20.0m);
decimal total = cart.CalculateTotal();
Console.WriteLine($"Cart total: ${total:F2}");
单一职责
单一职责意味着聚合根负责维护聚合内的一致性和业务规则,确保整个聚合的状态是有效的。
public class OrderItem
{
public int ProductId { get; }
public int Quantity { get; }
public decimal Price { get; }
public OrderItem(int productId, int quantity, decimal price)
{
if (quantity <= 0)
throw new ArgumentException("Quantity must be greater than 0");
if (price < 0)
throw new ArgumentException("Price must be non-negative");
ProductId = productId;
Quantity = quantity;
Price = price;
}
}
public class Order
{
public int OrderId { get; }
public int CustomerId { get; }
private List<OrderItem> Items { get; }
public Order(int orderId, int customerId)
{
OrderId = orderId;
CustomerId = customerId;
Items = new List<OrderItem>();
}
public void AddItem(int productId, int quantity, decimal price)
{
var item = new OrderItem(productId, quantity, price);
Items.Add(item);
}
public void RemoveItem(int productId)
{
Items.RemoveAll(item => item.ProductId == productId);
}
public decimal CalculateTotal()
{
return Items.Sum(item => item.Quantity * item.Price);
}
public IReadOnlyList<OrderItem> GetItems() => Items.AsReadOnly();
}
// 使用示例
var order = new Order(1, 1001);
order.AddItem(2001, 2, 10.0m);
order.AddItem(2002, 1, 20.0m);
decimal total = order.CalculateTotal();
Console.WriteLine($"Order total: ${total:F2}");
持久化控制
持久化控制意味着只有聚合根直接与持久化层交互,其内部的对象通常作为聚合的一部分被间接持久化。
public interface IOrderRepository
{
void Save(Order order);
Order GetById(int orderId);
}
public class OrderRepository : IOrderRepository
{
// 模拟持久化层,这里使用内存存储
private readonly Dictionary<int, Order> _storage = new Dictionary<int, Order>();
public void Save(Order order)
{
_storage[order.OrderId] = order;
}
public Order GetById(int orderId)
{
_storage.TryGetValue(orderId, out var order);
return order;
}
}
// 使用示例
var repository = new OrderRepository();
var order = new Order(1, 1001);
order.AddItem(2001, 2, 10.0m);
order.AddItem(2002, 1, 20.0m);
repository.Save(order);
var savedOrder = repository.GetById(1);
if (savedOrder != null)
{
decimal total = savedOrder.CalculateTotal();
Console.WriteLine($"Saved order total: ${total:F2}");
}
聚合根的重要性
聚合根在 DDD 中的作用类似于守护者,确保聚合内的数据和行为始终符合业务规则和不变性条件。通过聚合根来管理聚合,可以减少系统复杂性,提高系统的一致性和可靠性。
总结而言,聚合根是领域驱动设计中管理复杂领域模型的一种重要模式,它通过聚合内对象的一致性和不变性来简化业务逻辑的处理,并确保系统行为符合预期。