Kotlin中sealed class与sealed interface的区别及适用场景
Kotlin sealed interface 对比 sealed class 的优势与最佳实践
核心基础差异
两者都继承了sealed类型的核心特性:子类实现只能在同一个包下定义,when分支判断时可以自动做穷尽校验,不需要写else分支。除此以外,两者的差异完全对应普通类和接口的差异:
- sealed class 是类类型,有构造函数,可以存储公共状态、实现公共/私有方法,子类只能继承一个sealed父类,受Java单继承规则限制
- sealed interface 是接口类型,无构造函数,不能存储状态,默认所有方法都是公开抽象的,同一个类可以实现多个sealed interface
sealed interface 的独有优势
- 支持多实现:同一个业务类型可以同时归入多个密封体系,比如你定义
sealed interface Loadable用来标记可加载状态、sealed interface Refreshable用来标记可刷新状态,某个UI状态类可以同时实现这两个接口,在不同的业务判断场景下都能享受sealed类型的穷尽校验能力 - 支持枚举类实现:这是sealed class做不到的特性,你可以把固定枚举值和其他自定义类型共同归入同一个密封体系,示例如下:
sealed interface NavRoute { object Home : NavRoute // 枚举类实现sealed interface enum class SecondaryRoute : NavRoute { USER_CENTER, SETTING, MESSAGE_CENTER } data class Detail(val id: Long) : NavRoute }
- 类型建模更轻量:不需要强制继承类的额外特性,纯类型分类的场景下代码冗余度更低
选型判断与最佳实践
不需要所有简单场景都强制优先用sealed interface,根据实际需求判断即可:
优先选sealed interface的场景
- 密封体系下的子类不需要共享公共状态、不需要父类实现私有/非抽象公共方法
- 需要多实现、需要枚举类归入当前密封体系
- 用来定义事件、路由、操作符这类纯标记型的类型分类
必须选sealed class的场景
- 所有子类需要共享父类的公共状态、或者需要父类实现公共的复用方法/私有方法
- 需要限制子类的构造逻辑,比如通过父类私有构造函数统一管控子类的实例化规则
举个直观示例:如果你的网络请求状态需要统一存储请求ID用于链路追踪,用sealed class更合适:
sealed class NetworkState(val requestId: String) { class Loading(requestId: String) : NetworkState(requestId) class Success(requestId: String, val data: Any) : NetworkState(requestId) class Error(requestId: String, val throwable: Throwable) : NetworkState(requestId) }
如果不需要统一存储公共状态,用sealed interface更灵活:
sealed interface NetworkState { object Loading : NetworkState data class Success(val data: Any) : NetworkState data class Error(val throwable: Throwable) : NetworkState }
内容的提问来源于stack exchange,提问作者Canato
相关产品推荐
相关产品推荐

