繁体   English   中英

Kotlin 密封类与使用多态性

[英]Kotlin sealed classes vs using polymorphism

我很好奇 Kotlin 文档中关于密封类的示例:

fun log(e: Error) = when(e) {
    is FileReadError -> { println("Error while reading file ${e.file}") }
    is DatabaseError -> { println("Error while reading from database ${e.source}") }
    is RuntimeError ->  { println("Runtime error") }
    // the `else` clause is not required because all the cases are covered
}

假设这些类定义如下:

sealed class Error

class FileReadError(val file: String): Error()
class DatabaseError(val source: String): Error()
class RuntimeError : Error()

过度使用多态性when使用有什么好处:

sealed class Error {
    abstract fun log()
}

class FileReadError(val file: String): Error() {
    override fun log() { println("Error while reading file $file") }
}
class DatabaseError(val source: String): Error() {
    override fun log() { println("Error while reading from database $source") }
}
class RuntimeError : Error() {
    override fun log() { println("Runtime error") }
}

我能想到的唯一原因是我们可能无法访问这些类的源代码,无法将我们的log方法添加到它们中。 否则,与实例检查相比,多态性似乎是更好的选择(例如参见 [ 1 ] 或 [ 2 ]。)

这在Robert C. Martin 的《Clean Code: A Handbook of Agile Software Craftsmanship 》一书中被描述为“数据/对象反对称”。

在第一个示例(数据样式)中,您使用处理所有类型的外部函数使错误类保持哑巴状态。 这种风格与使用多态性(对象风格)相反,但也有一些优点。

假设您要添加一个新的外部函数,该函数会在发生错误时返回一个图标以向用户显示。 第一个优点是您可以轻松添加此图标功能,而无需更改任何错误类中的任何行并将其添加到一个地方。 第二个优势是分离。 也许您的错误类存在于项目的域模块中,并且您更希望图标功能位于项目的 ui 模块中以分离关注点。

因此,当保持密封类哑时,添加新函数和分离它们很容易,但很难添加新的错误类,因为那样你需要查找和更新每个函数。 另一方面,当使用多态性时,很难添加新的功能,而且您不能将它们与类分开,但是添加新的类很容易。

第一个(类型检查)示例的好处是不必将日志消息硬编码到Error子类中。 这样,客户端可能会在应用程序的不同部分为同一个Error子类记录不同的消息。

第二种(多态)方法假设每个人都希望每个错误都有相同的消息,并且每个子类的开发人员都知道该错误消息对于所有未来的用例应该是什么。

第一个示例中存在第二个示例中不存在的灵活性元素。 @Trevor 之前的回答检查了这种灵活性的理论基础。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM