with one click
aggregate
以聚合根为边界,包含多个相关Entity和ValueObject的集合。保证数据一致性和事务边界。
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
以聚合根为边界,包含多个相关Entity和ValueObject的集合。保证数据一致性和事务边界。
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
在DDD中具有唯一身份标识和生命周期的对象,通过身份而非属性值相等判断。
封装复杂对象和聚合的创建过程,将创建职责从领域对象中剥离,保证聚合创建时的不变量满足。
没有身份标识,通过属性值判断相等的对象。不可变,通常代表领域中的度量或描述。
命令查询责任分离,将数据的写入操作和读取操作分别用不同的模型处理,优化各自的性能。
将DDD战略设计应用于微服务架构,限界上下文指导服务拆分,领域事件实现服务间通信。
对比 MVC 模式与 DDD 方法论的差异,分析 MVC 在复杂业务下的局限性,帮助团队判断何时应采用 DDD。
| name | 聚合 (Aggregate) |
| description | 以聚合根为边界,包含多个相关Entity和ValueObject的集合。保证数据一致性和事务边界。 |
Eric Evans 将聚合定义为:一组相关对象的集合,作为数据变更的整体单元("a cluster of associated objects that we treat as a unit for the purpose of data changes")。每个聚合都有一个聚合根——作为外部访问聚合内部对象的唯一入口,以及一条由根的标识划定的一致性边界。
核心概念:
// 聚合根:Order
public class Order {
private final String orderId;
private List<OrderLine> items; // 从属于聚合
private OrderStatus status;
private Money totalAmount;
public void addItem(Product product, int quantity) {
OrderLine line = new OrderLine(product, quantity);
items.add(line);
recalculateTotal();
}
public void cancel() {
if (!canBeCanceled()) {
throw new IllegalStateException("Cannot cancel order");
}
this.status = OrderStatus.CANCELED;
}
// 只通过聚合根修改数据,不直接访问items
// ❌ 不要:order.getItems().add(...);
// ✅ 要:order.addItem(...);
private void recalculateTotal() {
totalAmount = items.stream()
.map(OrderLine::getTotal)
.reduce(Money.ZERO, Money::add);
}
private boolean canBeCanceled() {
return status == OrderStatus.PENDING || status == OrderStatus.PAID;
}
}
// OrderLine:聚合内的对象,不应该独立存在
public class OrderLine {
private final Product product;
private final int quantity;
public Money getTotal() {
return product.getPrice().multiply(quantity);
}
}
class Order:
def __init__(self, order_id: str, customer_id: str):
self.order_id = order_id
self.customer_id = customer_id
self.items = []
self.status = "PENDING"
self.total_amount = Money(0, "USD")
def add_item(self, product: 'Product', quantity: int):
"""通过聚合根添加项"""
line = OrderLine(product, quantity)
self.items.append(line)
self._recalculate_total()
def can_be_canceled(self) -> bool:
return self.status in ["PENDING", "PAID"]
def cancel(self):
if not self.can_be_canceled():
raise ValueError("Cannot cancel order")
self.status = "CANCELED"
def _recalculate_total(self):
self.total_amount = sum(
(line.get_total() for line in self.items),
Money(0, "USD")
)
class OrderLine:
def __init__(self, product: 'Product', quantity: int):
self.product = product
self.quantity = quantity
def get_total(self) -> 'Money':
return self.product.price.multiply(self.quantity)
// ❌ 错误:从外部直接访问聚合内部
Order order = orderRepository.find("O001");
OrderLine line = order.getItems().get(0); // 直接访问!
line.setQuantity(100); // 修改!
// ✅ 正确:通过聚合根
Order order = orderRepository.find("O001");
order.updateItem(0, 100); // 通过聚合根修改
Vaughn Vernon 在 Implementing Domain-Driven Design(IDDD,红皮书)中提炼了四条被广泛认可的聚合设计经验:
// ✅ 遵循规则:小聚合 + ID 引用
public class Order {
private OrderId id;
private CustomerId customerId; // 通过 ID 引用其他聚合,而非 Customer 对象
private List<OrderLine> items; // 聚合内部实体
private OrderStatus status;
}
// ❌ 违反规则:穿透边界、对象引用
public class Order {
private Customer customer; // 直接持有另一聚合的对象引用
private List<OrderLine> items;
public void changeCustomerEmail(String email) {
customer.setEmail(email); // 跨聚合直接写——破坏单写规则
}
}
"小聚合"是原则,但"多小才算小"没有标准答案。下列实操判据可帮助判断:
判断聚合是否过大:
判断聚合是否过小(被切碎了):
经验判据:
❌ 上帝聚合——把 Order + Customer + Product + Inventory 全塞进一个根 → 用 ID 引用其他聚合,每个聚合只承载自己的真实不变量
❌ 从外部直接操作聚合内部对象——order.getItems().add(...) 跳过聚合根校验
→ 暴露行为方法 order.addItem(...),集合修改入口只在聚合根内部
❌ 跨聚合写在一个事务里——一次事务同时更新 Order、Inventory、Payment → 同一事务只改一个聚合,跨聚合协同用领域事件 + 最终一致性
聚合是建立清晰边界、保证数据一致的关键设计。