用密封类构建adt本质是将“有限、封闭、不可变”的业务概念编码进类型系统,通过sealed interface定义契约、record实现不可变变体、switch强制穷尽处理,并天然形成跨上下文防腐层。

用密封类构建代数数据类型(ADT),本质是把“有限、封闭、不可变”的业务概念直接编码进类型系统——不是靠注释或约定,而是让编译器强制校验。
用 sealed interface 定义领域契约
选接口而非抽象类,语义更干净:它只声明“这个概念有哪些合法形态”,不掺杂行为实现。比如订单状态:
- 写成 public sealed interface OrderStatus permits Placed, Confirmed, Shipped, Cancelled {}
- 所有实现类必须在同一个模块内可见;默认模块下建议和接口放在同一文件
- permits 子句不能省略,漏写或拼错类名,编译直接失败
用 record 实现不可变变体
每个变体对应一个确定的业务事实,天然适合 record:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- public final record Placed(Instant placedAt, String orderRef) implements OrderStatus {}
- 字段自动 final,构造器、equals、hashCode、toString 全部自动生成
- 显式加 final 更安全——哪怕 record 默认 final,写出来能防误改、提升可读性
用 switch 表达式强制穷尽处理
消费逻辑不再靠 instanceof 或 if-else 硬判断,而是由编译器盯住你是否覆盖全部状态:
- 写法:return switch (status) { case Placed p -> "已下单"; case Confirmed c -> "已确认"; ... };
- 漏掉任一 permits 列出的类型,或某个实现类不是 final,编译报错
- 禁止加 default 分支——这逼你回答:这个状态真的不该出现?还是我还没想全?
跨上下文协作时自动形成防腐层
当订单状态要传给物流服务,密封体系天然支持 ACL 设计:
- 物流只接收 OrderStatus,不依赖具体类名,解耦明确
- 它必须显式处理每种状态,无法忽略 Shipped 或假装“兼容未来类型”
- record 的不可变性防止状态在传递中被意外修改
- 其他包试图新增实现?编译器直接拦截,连运行都跑不起来










