如何覆盖密封的类字段?

问题描述

我在我的服务中创建了一个自定义结果字段(而不是 Kotlin 的结果),因此我可以在成功和失败案例中返回一个消息字段:

sealed class Result<T> {
    data class Success<T>(val value: T,val message: String) : Result<T>()

    data class Failure<T>(val throwable: Throwable? = null,val message: String) : Result<T>() {
        val isExceptional = throwable != null
        val error: Throwable
            get() = throwable ?: error("Error is undefined in [$this]")
    }
}

然后在另一个类中我调用一个产生这个结果的方法,并想记录 Result.message

logger.info { "Finished with message [${result.message}]." }

只是,kotlin 编译器不识别“消息”,因为它不是直接的 Result 属性,而是 Success 和 Failure 的属性

我试图覆盖消息字段并在 Result 类中定义它。但我收到一个错误

Error:(10,38) Kotlin: 'message' in 'Result' is final and cannot be overridden

那么,如何访问 Result.message 而不将结果实例转换为它的派生实现类(成功或失败)?

解决方法

1- 您可以将它们标记为打开

open val message: String = ""

2- 你可以定义它们抽象

abstract val message: String
,

您可以在 Result 类中声明抽象属性:

sealed class Result<T> {
    abstract val message: String
    data class Success<T>(val value: T,override val message: String) : Result<T>()

    data class Failure<T>(val throwable: Throwable? = null,override val message: String) : Result<T>() {
        val isExceptional = throwable != null
        val error: Throwable
            get() = throwable ?: error("Error is undefined in [$this]")
    }
}

不过,您的解决方案也是一种选择

,

我找到的一个干净的解决方案如下。

虽然 Kotlin 不允许我们覆盖密封的类成员。它确实允许我们覆盖接口成员。

因此,我为消息字段创建了一个简单的接口,并从 Result 类中实现:

interface ResultMessage {
    val message: String
}

sealed class Result<T> : ResultMessage

// Now I'm able to override the message field simply,with no error
data class Success<T>(val value: T,override val message: String) : Result<T>()

data class Failure<T>(val throwable: Throwable? = null,override val message: String) : Result<T>() {
    val isExceptional = throwable != null
    val error: Throwable
        get() = throwable ?: error("Error is undefined in [$this]")
}