简体   繁体   English

Kotlin 密封类与使用多态性

[英]Kotlin sealed classes vs using polymorphism

I'm curious about an example given in Kotlin documentation regarding sealed classes :我很好奇 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
}

Let's imagine the classes are defined as follows:假设这些类定义如下:

sealed class Error

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

Is there any benefit for using when over using polymorphism:过度使用多态性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") }
}

The only reason I can think of is that we may not have access to the source code of those classes, in order to add our log method to them.我能想到的唯一原因是我们可能无法访问这些类的源代码,无法将我们的log方法添加到它们中。 Otherwise, it seems that polymorphism is a better choice over instance checking (see [ 1 ] or [ 2 ] for instance.)否则,与实例检查相比,多态性似乎是更好的选择(例如参见 [ 1 ] 或 [ 2 ]。)

This is described as "Data/Object Anti-Symmetry" in the book Clean Code: A Handbook of Agile Software Craftsmanship by Robert C. Martin .这在Robert C. Martin 的《Clean Code: A Handbook of Agile Software Craftsmanship 》一书中被描述为“数据/对象反对称”。

In the first example (Data style), you are keeping your error classes dumb with an external function that handles all types.在第一个示例(数据样式)中,您使用处理所有类型的外部函数使错误类保持哑巴状态。 This style is in opposition to using polymorphism (Object style) but there are some advantages.这种风格与使用多态性(对象风格)相反,但也有一些优点。

Suppose you were to add a new external function, one that returns an icon to show the user when the error happens.假设您要添加一个新的外部函数,该函数会在发生错误时返回一个图标以向用户显示。 The first advantage is you can easily add this icon function without changing any line in any of your error classes and add it in a single place.第一个优点是您可以轻松添加此图标功能,而无需更改任何错误类中的任何行并将其添加到一个地方。 The second advantage is in the separation.第二个优势是分离。 Maybe your error classes exist in the domain module of your project and you'd prefer your icon function to be in the ui module of your project to separate concerns.也许您的错误类存在于项目的域模块中,并且您更希望图标功能位于项目的 ui 模块中以分离关注点。

So when keeping the sealed classes dumb, it's easy to add new functions and easy to separate them, but it's hard to add new classes of errors because then you need to find and update every function.因此,当保持密封类哑时,添加新函数和分离它们很容易,但很难添加新的错误类,因为那样你需要查找和更新每个函数。 On the other hand when using polymorphism, it's hard to add new functions and you can't separate them from the class, but it's easy to add new classes.另一方面,当使用多态性时,很难添加新的功能,而且您不能将它们与类分开,但是添加新的类很容易。

The benefit of the first (type-checking) example is that the log messages do not have to be hardcoded into the Error subclasses.第一个(类型检查)示例的好处是不必将日志消息硬编码到Error子类中。 In this way, clients could potentially log different messages for the same subclass of Error in different parts of an application.这样,客户端可能会在应用程序的不同部分为同一个Error子类记录不同的消息。

The second (polymorphic) approach assumes everyone wants the same message for each error and that the developer of each subclass knows what that error message should be for all future use cases.第二种(多态)方法假设每个人都希望每个错误都有相同的消息,并且每个子类的开发人员都知道该错误消息对于所有未来的用例应该是什么。

There is an element of flexibility in the first example that does not exist in the second.第一个示例中存在第二个示例中不存在的灵活性元素。 The previous answer from @Trevor examines the theoretical underpinning of this flexibility. @Trevor 之前的回答检查了这种灵活性的理论基础。

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

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