密封类配合多态的核心是将多态分支收束至编译期可穷举、ide可感知、运行时可保障的有限集合,解决新增子类型时逻辑遗漏问题;通过permits显式声明子类型契约,record实现不可变语义化数据,switch模式匹配强制覆盖所有分支,并自然融合领域事件与策略模式。

用密封类(sealed)配合多态,核心不是“让子类自由扩展”,而是**把多态的分支收束到编译期可穷举、IDE可感知、运行时可保障的有限集合中**。这种结合直接解决传统多态最脆弱的一环:新增子类型时逻辑遗漏——比如支付回调漏处理新渠道、订单状态新增后校验逻辑未覆盖,这类问题在生产环境极易引发资损。
明确声明封闭的类型边界:permits 是契约,不是装饰
密封类必须显式列出所有合法子类型,这是强制性的语义契约:
-
接口或抽象类加
sealed关键字,后面紧跟permits A, B, C,中间不能有省略号或通配符 -
每个被允许的子类必须声明修饰符:用
final(彻底封闭)、sealed(继续向下密封)、或non-sealed(开放继承,慎用) -
编译器会严格检查:如果新增一个类实现该密封接口但没写进
permits,或子类没加对应修饰符,直接报错,不给上线留隐患
用 record 实现子类:不可变 + 零样板 + 语义即数据
90% 的业务域模型本质是“带行为的数据容器”,record 天然匹配:
- 每个具体状态(如
Pending、Success(String txId)、Failure(String reason))用record实现,自动获得构造器、字段访问器、equals/hashCode/toString - 不可变性杜绝状态中途被篡改,符合领域建模中“状态实例即事实”的原则
- 字段名和类型直接暴露语义(
Success(String txId)比Success{txId="abc123"}更清晰),也便于后续模式匹配解构
多态逻辑落地在 switch 表达式:编译器替你查漏
不再用 if-else 或 instanceof 链,而是用支持模式匹配的 switch:
-
分支与
permits列表完全对齐:只要密封类型有且仅有 A/B/C 三种实现,switch 就必须写出case A:、case B:、case C: -
IDE 实时提示缺失分支:新增一个
Timeoutrecord 并加入permits后,所有已有 switch 语句立刻标红,强制补全处理逻辑 -
自动类型解构:写
case Success(String txId) -> "Tx: " + txId,编译器知道txId是String,无需手动强转
与领域事件、策略模式自然融合:安全不是代价,是设计起点
密封类不是把架构变重,而是让关键决策点更轻、更稳:
- 订单状态机:
sealed interface OrderStatus permits Draft, Confirmed, Shipped, Cancelled,每个状态 record 可封装其专属行为(如Confirmed有canRefund(),Cancelled有reason()) - 风控策略:
sealed interface RiskRule permits AmountLimit, DeviceFingerprint, GeoBlocking,策略执行器用 switch 分发,新增规则时必须同步补充规则加载、执行、降级逻辑 - 外部系统适配:
sealed interface PaymentGateway permits Alipay, WechatPay, UnionPay,网关路由层天然穷尽,不会因漏配导致调用空指针或静默失败
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











