java中ddd封装的核心是“只允许按业务规则改”聚合根状态,通过private字段、受控行为方法、垄断子对象生命周期、实时不变量检查及id唯一引用实现。

Java 中封装在领域驱动设计(DDD)中保护聚合根状态,核心不是“不让改”,而是“只允许按业务规则改”。这靠的是面向对象的封装机制与领域建模原则的深度结合——私有字段 + 受控方法 + 明确边界。
用 private 字段封死直接赋值通道
聚合根内部的状态变量必须声明为 private,禁止外部通过 order.status = "shipped" 这类裸赋值绕过校验。哪怕只是简单字段,也要切断反射以外的所有直接写入路径。比如:
public class Order {
private String status; // 不是 public 或 protected
private BigDecimal total;
private List<orderitem> items;
// 构造时即确立初始状态,不允许后续无约束变更
private Order(String id, BigDecimal total) {
this.id = id;
this.total = total;
this.status = "draft";
this.items = new ArrayList();
}
}</orderitem>
所有状态变更必须走显式行为方法
每个可能改变状态的操作,都对应一个有业务语义的方法,方法内嵌入不变量检查和规则执行。例如:
-
confirm():检查是否已支付、库存是否充足、地址是否完整 -
ship():确认订单状态为confirmed,且所有商品可履约 -
cancel():拒绝已发货或已完成的订单
这些方法不返回 void 就是陷阱;它们应返回 this 或抛出明确的领域异常(如 OrderAlreadyShippedException),让调用方感知失败语义。
聚合根垄断子对象生命周期与访问路径
子实体(如 OrderItem)不能被外部直接 new 或 set,只能由聚合根创建、修改、删除。外部代码无法拿到 OrderItem 的引用去调用其 setter——它要么是 private final,要么暴露为不可变视图(如 Collections.unmodifiableList(items))。聚合根之外,没有其他入口能触达内部状态。
不变量检查必须嵌入行为,而非延迟到持久化前
比如“订单总金额必须等于各明细之和”这条规则,不能靠数据库 check constraint 或 service 层事后校验。它应在 addItem()、removeItem()、updateQuantity() 等每个影响金额的操作里实时验证,并在不满足时立即中断。
ID 是唯一合法外部引用点,禁止跨聚合直连实体
其他聚合(如 Payment)只能持有 Order 的 ID(如 orderId),不能持有 Order 实例引用。若需协同,必须通过应用服务协调两个聚合根,或发布/订阅领域事件。这从架构层面杜绝了绕过聚合根修改内部状态的可能性。
本质上,Java 封装在这里不是语法习惯,而是建模纪律:把业务规则编码进方法签名与执行逻辑中,让编译器和运行时共同守住那条“状态只能经行为流变”的底线。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











