限制类成员变量可见性是为了确保状态变更经受控路径,实体是业务规则执行体而非数据容器;聚合根垄断子对象生命周期;不变量检查嵌入行为方法;用领域异常明确表达业务失败。

限制类成员变量的可见性,不是为了“不让别人看见”,而是为了确保所有状态变更都必须经过受控的行为路径。这是领域驱动设计中实体封装的根基。
用 private 封住直接赋值的后门
实体不是数据容器,是业务规则的执行体。一旦允许 order.status = "paid" 这样的直写,就绕过了“已取消订单不可支付”“余额不足禁止扣款”等核心校验。
- Java/Kotlin/C# 中,把字段声明为 private final,只提供带校验逻辑的 public 方法(如
confirmPayment()、cancel()) - Python 中虽无真正 private,但应统一用单下划线前缀(
_status),并配合@property和@setter插入状态流转校验 - 禁止暴露公共 setter;所有修改入口必须是语义明确的方法,比如
addItem(item),而不是setItems(List<item>)</item>
聚合根垄断子对象生命周期
子对象(如 OrderItem)不是独立存在,它的创建、访问、修改都必须由聚合根统一管控,否则一致性无法保障。
-
OrderItem类不提供 public 构造函数,只允许Order.add_item()内部调用其私有构造或工厂方法 - 外部不能持有
OrderItem引用,更不能调用item.update_price();所有操作必须走order.update_item_price(id, new_price),确保总价同步更新 - 聚合根内部可用
List<_orderitem></_orderitem>存储,但对外只暴露不可变视图(如unmodifiableList或只读接口)
把不变量检查嵌入行为方法中
私有字段 + 显式方法的组合,天然构成插入校验、事件发布、审计日志的钩子点。这是贫血模型做不到的控制力。
- 在
@status.setter中判断状态跳转合法性:if self._status == "cancelled": raise DomainError("Cannot pay cancelled order") - 在
add_item()中校验库存、触发ItemAddedEvent、更新_total_amount - 重写
__eq__和__hash__时,只基于不可变标识(如_id),不依赖可变字段(如_status),保证实体身份一致性
用领域异常明确表达业务失败
封住字段不是掩盖错误,而是让错误更有意义。抛出的异常必须是业务语言,不是技术报错。
- 避免泛化异常如
RuntimeException或IllegalArgumentException - 定义清晰的领域异常类型:如
InsufficientBalanceException、InvalidStatusTransitionException - 异常消息应说明“为什么不能做”,便于前端展示或日志归因,例如 "订单已发货,不可再修改收货地址"











