问题历史:
带有sealed修饰符的接口在Kotlin中作为sealed class概念的发展而出现。在Kotlin 1.5之前,只有sealed类允许限制可能的子类,这在安全处理状态机(state machines,DSL等)的层次结构中尤其重要。引入sealed接口后,开发者能够类似地限制接口的实现,而不依赖于类。
问题:
简单的开放接口可以在程序中的任何地方实现,这可能导致实现数量无法控制并使代码维护变得复杂。在通过when表达式处理时,编译器无法警告未考虑的分支。
解决方案:
Sealed interface仅限制在一个模块(或者同一个文件中,若接口不是顶级的)中定义的实现。这种控制方法用于安全的类似枚举的结构、ADT模式和状态处理程序。编译器知道所有实现并在代码分析中提供帮助。
代码示例:
sealed interface NetworkResult class Success(val data: String): NetworkResult class Error(val cause: Throwable): NetworkResult object Loading: NetworkResult fun handleResult(result: NetworkResult): String = when (result) { is Success -> "Success with ${result.data}" is Error -> "Error: ${result.cause.message}" Loading -> "Loading..." }
关键特点:
可以在当前文件之外实现sealed接口吗?
回答:与sealed类不同,sealed接口可以在其他文件中实现,但仅限于当前模块(或编译单元,如果接口不是顶级的)。
sealed接口可以具有默认实现的开放方法吗?
可以,像普通接口一样,sealed接口可以包含函数的默认实现。
sealed interface Mode { fun description(): String = "Unknown mode" }
可以通过标准序列化器(例如,kotlinx.serialization)序列化sealed接口吗?
可以,但需要明确指定所有实现。在Kotlinx.serialization中,sealed接口的支持并不是立刻出现的,明确指定待序列化的类型非常重要。
在项目中描述了所有UI状态类型的sealed接口,而实现开始出现在应用程序的不同部分。后来添加了新的状态类型,忘记更新处理块,导致在日志中忽略新状态。
优点:
缺点:
使用sealed接口处理所有网络响应。这样,在添加新响应类型时,IDE立即标记了通过when处理的所有地方。错误立即被修复,逻辑中没有意外的孔洞。
优点:
缺点: