如何通过Sealed Classes构建领域驱动设计中的受限代数数据类型?
- 内容介绍
- 相关推荐
本文共计848个文字,预计阅读时间需要4分钟。
Java 的密封类(`sealed`)配合 `record`,为数据类型(ADT)的量身定制提供了原生支持。它不依赖于接口模拟或抽象类,也不依赖手写的子类模板,而是通过编译器强制保证:
典型场景比如支付方式、订单状态、解析结果这类“有限且封闭”的业务概念——它们天然不是开放扩展的,而是有明确、固定种类的。这时候用 sealed interface 定义契约,用 record 实现具体变体,语义清晰、不可变、无冗余代码。
必须满足的三个语法硬约束
漏掉任意一条,编译直接报错,不是运行时问题:
-
sealed接口或类必须显式带permits子句(除非所有子类与它在同一源文件中,此时可省略) - 每个被
permits列出的实现类/子类,必须声明为final、sealed或non-sealed -
record实现密封接口时,必须加final(哪怕不写,record 默认就是 final,但显式写上更安全、可读性更强)
switch 表达式能做穷尽检查的关键条件
只有当所有分支都覆盖了 permits 列出的类型,且这些类型本身是 final(或至少没有额外子类),编译器才允许你省略 default 分支。否则会报错:the switch expression does not cover all possible values。
本文共计848个文字,预计阅读时间需要4分钟。
Java 的密封类(`sealed`)配合 `record`,为数据类型(ADT)的量身定制提供了原生支持。它不依赖于接口模拟或抽象类,也不依赖手写的子类模板,而是通过编译器强制保证:
典型场景比如支付方式、订单状态、解析结果这类“有限且封闭”的业务概念——它们天然不是开放扩展的,而是有明确、固定种类的。这时候用 sealed interface 定义契约,用 record 实现具体变体,语义清晰、不可变、无冗余代码。
必须满足的三个语法硬约束
漏掉任意一条,编译直接报错,不是运行时问题:
-
sealed接口或类必须显式带permits子句(除非所有子类与它在同一源文件中,此时可省略) - 每个被
permits列出的实现类/子类,必须声明为final、sealed或non-sealed -
record实现密封接口时,必须加final(哪怕不写,record 默认就是 final,但显式写上更安全、可读性更强)
switch 表达式能做穷尽检查的关键条件
只有当所有分支都覆盖了 permits 列出的类型,且这些类型本身是 final(或至少没有额外子类),编译器才允许你省略 default 分支。否则会报错:the switch expression does not cover all possible values。

