核心业务实体边界须由语言机制锁定而非注释:用file类、fileprivate等限制可见性;封装辅助逻辑为文件级私有;返回不可变视图;聚合根收口所有交互;对外仅暴露接口契约。

核心业务实体内部的边界不是靠注释或文档划出来的,而是靠语言机制和设计约束真正“锁住”的。限制捕获块(如 C# 的 file 类型、Java 的包私有作用域、Swift 的 fileprivate)本质是把“可见性”作为第一道防线,在编译期就切断外部对内部实现的窥探与依赖。
用文件级作用域封住实体的辅助逻辑
业务实体(如 Order)常需配套状态校验器、临时转换器或本地缓存策略——这些不是领域行为,只是支撑主逻辑的“脚手架”。若暴露为 public 类,就会诱使其他模块绕过接口直接调用,破坏封装。
- 在 C# 11+ 中,用
file class OrderValidator声明校验逻辑,仅限当前Order.cs文件内使用 - 避免写
public static bool IsValid(...)工具方法,它会成为跨模块引用的漏洞入口 - 同理,Swift 中用
fileprivate struct LocalCache封装实体内部缓存,不参与模块导出
禁止返回可变内部状态,切断变量外溢链路
捕获块本身不能防止 getter 泄露可变对象。强内聚要求:实体对外只提供不可变视图,所有中间状态必须被“冻结”后才离开边界。
-
public IReadOnlyList<orderitem> Items => _items.AsReadOnly();</orderitem>(而非直接返回_items) - 避免
public Dictionary<string object> GetMetadata()</string>,改用public record Metadata(string Status, DateTime Updated) - 构造时即固化状态:
private readonly List<orderitem> _items = new();</orderitem>+private readonly string _id;
将聚合根作为唯一合法出口,收口所有交互路径
一个订单聚合不应允许外部直接操作其子项或版本号。所有变更必须经由聚合根定义的语义方法触发,而这些方法本身应位于同一捕获块内,确保逻辑闭环。
-
public void Cancel(CancellationReason reason)内部调用file static void ApplyCancellation(...) - 禁止暴露
public OrderItem FirstItem { get; },改为public OrderItem GetItemById(string id)(含存在性校验) - 事件发布也收束于聚合内:
file void RaiseOrderCancelledEvent(),不暴露IEventBus实例
用接口契约替代类型暴露,让边界可验证不可绕过
即使用了 file 修饰,若接口返回具体类型(如 OrderService.Create() 返回 Order 类),外部仍可能反向依赖其实现细节。真正的边界需要抽象层兜底。
- 对外只暴露
IOrder接口,Order类本身设为file或internal - 工厂方法也封装在同文件:
file static IOrder CreateFromDto(OrderDto dto) - 单元测试可通过接口注入验证,但无法 new 出
Order实例进行反射或字段篡改










