Kotlin-有没有一种方法可以定义函数的显式范围,而该对象必须在伴随对象中定义?

时间:2020-10-29 15:24:15

标签: kotlin kotlin-extension

假设您有以下代码:

interface SomeClient {

    fun isValid(value: String): Boolean
}

class SomeData private constructor(
    val value: String
) {

    companion object {

        fun SomeClient.create(value: String): SomeData? =
            if (isValid(value)) {
                SomeData(value)
            } else {
                null
            }
    }
}

class SomeOtherData private constructor(
    val otherValue: String
) {

    companion object {

        fun SomeClient.create(value: String): SomeOtherData? =
            if (isValid(value)) {
                SomeOtherData(value)
            } else {
                null
            }
    }
}

class SomeUseCase(
    someClient: SomeClient
) : SomeClient by someClient {

    fun run() {
        val someData = SomeData.create("hello")
        val someOtherData = SomeOtherData.create("wassup")
    }
}

整个目的是提供一种静态工厂方法来创建有效的值对象(SomeDataSomeOtherData),但是验证逻辑包括一些IO操作。因此,我想将可调用create方法的范围限制为实现SomeClient的类。

这里的问题是,编译器无法解析SomeData#create内的伴随对象方法(SomeOtherData#createSomeUseCase#run),它抱怨接收者不正确。

我当然可以那样做

class SomeUseCase {
    fun run() {
        val someData = this.createSomeData(...)
        val someOtherData = this.createSomeOtherData(...)
    }
}

并相应地重命名创建方法,但我想保留名称,使其为SomeData.create,而不是SomeData.createSomeData

有没有办法做到这一点?真的有道理吗?

1 个答案:

答案 0 :(得分:2)

fun SomeClient.create(value: String)随播对象中编写SomeData时,您不是在为随播对象定义create方法,而是在SomeClient的范围内为isValid定义extension function随播对象。

如果重写它使其成为伴侣对象的方法,您将看到class SomeData private constructor(val value: String) { companion object { fun create(value: String, validator: SomeClient): SomeData? = if (validator.isValid(value)) SomeData(value) else null } } ()调用没有接收者,因此需要将其作为参数传递给该接收者:

SomeClient

之后,可以在val someData = SomeData.create("hello", this) 范围内这样调用它:

this

对于每个创建调用重复SomeData有点麻烦,因此您可以在SomeClient接口范围内为interface SomeClient { fun isValid(value: String): Boolean fun SomeData.Companion.create(value: String) = create(value, this@SomeClient) } 伴随对象定义扩展功能:

SomeClient

此后,可以按所需方式在val someData = SomeData.create("hello") 范围内调用它:

locale