领域战术建模:解密聚合工厂(Factory)与构建器(Builder)的实例化设计
在领域驱动设计(DDD)的战术装配中,**聚合根(Aggregate Root)**代表了一个严密的业务逻辑边界。在聚合根的生命周期中,有两个关键的高频场景:一是“新聚合根的诞生(创建)”;二是“已有聚合根的重建(从数据库载入)”。
如果一个聚合的内部关系极其复杂(包含多个实体、值对象,以及严格的不变性业务规则),如果我们直接在聚合根的构造函数中编写冗长复杂的装配和校验代码,会导致构造函数极度臃肿,且违反“单一职责原则”。
为了将**“复杂聚合的实例化与构建过程”**与**“聚合根自身的业务行为”**彻底解耦,DDD 引入了**领域工厂(Domain Factory)**与**构建器模式(Builder Pattern)**。
本文将系统拆解领域工厂与构建器的职责定位对比、不变性规则的强校验时机、以及标准的工程代码落地。
一、 职责拆解:领域工厂 vs. 构建器模式
虽然二者都用于实例化聚合根,但在处理复杂的业务关系和装配深度时,职责定位有本质不同:
| 特征维度 | 构建器模式 (Builder Pattern) | 领域工厂 (Domain Factory) |
|---|---|---|
| 核心职责 | 分步、灵活地组装复杂聚合的各个**内部零部件(属性、实体、值对象)**。 | 一键、原子化地完成一个聚合根的**生命周期诞生**。 |
| 知识内聚性 | 关注“如何构建”的技术细节。 | 关注“业务用例”的生命周期语义。往往内聚了特定的业务规则判定。 |
| 不变性校验 (Validation) | 通常在最后的 .build() 方法中触发物理边界与数据格式校验。 | 在工厂方法的入口和返回前,强行校验多维业务边界规则。 |
| 与仓储(Repository)关系 | 无。通常只是纯粹的内存对象拼装。 | 紧密配合。仓储从 DB 读取原始 PO 并还原为领域实体时,常调用重建工厂(Rebuild Factory)。 |
二、 聚合实例化与重建的数据流转拓扑
当一个全新的订单诞生,或者从底层数据库读取数据重建时,领域工厂与构建器的协作拓扑如下:
[ 新订单创建用例 (Application Service) ]
│
▼ 1. 调用一键诞生工厂
[ 领域工厂 (OrderFactory) ]
│
▼ 2. 调度构建器组装属性
[ 构建器 (OrderBuilder) ]
│
┌───────────────┴───────────────┐
▼ 3. 组装订单项 ▼ 4. 组装送货值对象
[ 订单项实体 (OrderItem) ] [ 地址值对象 (Address) ]
└───────────────┬───────────────┘
│
▼ 5. build() 并触发边界校验
[ 聚合根实体 (SalesOrder) ] ──> 6. 成功返回应用服务
---三、 代码实战:复杂订单聚合根的工厂与构建器装配
以下代码展示了如何在 Java 中定义支持级联构建的构建器,并通过领域工厂强行校验“订单初始金额必须大于零”等业务不变性规则:
1. 领域层:充血的订单聚合根(Domain Layer)
package com.company.sales.domain.model;
import java.util.*;
public class SalesOrder {
private final String orderId;
private final String customerId;
private final List<OrderItem> items;
private final double totalAmount;
// 限制为 package-private 构造,强迫外部只能通过 Builder 或 Factory 进行实例化
SalesOrder(String orderId, String customerId, List<OrderItem> items, double totalAmount) {
this.orderId = orderId;
this.customerId = customerId;
this.items = items;
this.totalAmount = totalAmount;
}
public String getOrderId() { return orderId; }
public double getTotalAmount() { return totalAmount; }
}
2. 领域层:级联构建器(OrderBuilder)
package com.company.sales.domain.model;
import java.util.*;
public class OrderBuilder {
private String orderId;
private String customerId;
private final List<OrderItem> items = new ArrayList<>();
private double totalAmount;
public OrderBuilder withOrderId(String orderId) {
this.orderId = orderId;
return this;
}
public OrderBuilder withCustomerId(String customerId) {
this.customerId = customerId;
return this;
}
public OrderBuilder addItem(String sku, int quantity, double price) {
this.items.add(new OrderItem(sku, quantity, price));
this.totalAmount += price * quantity;
return this;
}
public SalesOrder build() {
// 1. 基础格式校验
if (orderId == null || customerId == null) {
throw new IllegalArgumentException("订单 ID 与客户 ID 不能为空!");
}
if (items.isEmpty()) {
throw new IllegalStateException("订单项不能为空!");
}
// 2. 返回装配完成的聚合根
return new SalesOrder(orderId, customerId, items, totalAmount);
}
}
3. 领域层:高内聚领域工厂(OrderFactory)
package com.company.sales.domain.model;
import java.util.UUID;
/**
* 订单领域工厂
*/
public class OrderFactory {
/**
* 业务用例一键诞生工厂:负责生成全新 ID 并校验特定初始业务规约
*/
public static SalesOrder createNewOrder(String customerId, String sku, int quantity, double price) {
// 不变性约束校验:首单金额不能低于 10 元
double expectedAmount = price * quantity;
if (expectedAmount < 10.0) {
throw new IllegalArgumentException("新订单初始金额不能低于 10 元!");
}
// 一键快速装配
return new OrderBuilder()
.withOrderId(UUID.randomUUID().toString()) // 自动生成领域标识
.withCustomerId(customerId)
.addItem(sku, quantity, price)
.build();
}
}
---四、 总结
聚合工厂(Factory)与构建器(Builder)是保障聚合根内部复杂规则不外泄的“防火墙”。
It 通过**将复杂 of 级联实例化过程物理隔离到专用 of 构建类中,确保了聚合根构造函数 of 精简与高内聚,维护了聚合 of 不变性边界;并区分了业务诞生与数据重建 of 技术通道,保障了领域层逻辑 of 纯净**。掌握这套工厂与构建器 of 搭配使用,是治理复杂微服务聚合装配、提升核心代码内聚性 of 核心看家本领!
本站所有文章、数据、图片均来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。



暂无评论
还没有人评论过本文,快来发表你的高见吧!