使用子类分配Kotlin var

时间:2018-03-01 16:12:04

标签: kotlin

我有以下类/接口:

interface A

interface Factory<in SpecType: Factory.Spec> {
    interface Spec
    fun create(spec: SpecType): A
}

class DefaultFactory : Factory<DefaultFactory.Spec> {
    data class Spec(
        val message: String
    ) : Factory.Spec

    override fun create(spec: Spec): A {
      // Do stuff here to create an instance of A using spec
    }
}

然后在另一个班级,我想提供一个可以替换的默认工厂。

var factory: Factory<???> = DefaultFactory()

无论我似乎尝试替换???,我都无法让它运作良好。如果使用接受Spec的工厂然后传递给另一个工厂,我不介意在运行时崩溃。我发现的唯一有用的是:

@Suppress("UNCHECKED_CAST")
var factory: Factory<Factory.Spec> = DefaultFactory() as Factory<Factory.Spec>

但这看起来很丑陋而且似乎错了。

2 个答案:

答案 0 :(得分:0)

明显的答案是var factory:Factory<DefaultFactory.Spec> = DefaultFactory()

但我认为你需要更复杂的东西。

实际上你可能需要这样的提供者界面:

interface Factory<in SpecType: Factory.Spec> {
    interface Spec
    fun create(spec: SpecType): A
    val spec: SpecType
}

然后你的实现看起来像

class DefaultFactory : Factory<DefaultFactory.Spec> {
    override val spec: Spec
        get() = Spec("test message")
    override fun create(spec: Spec): A {
        TODO("not implemented")
    }
    data class Spec(val message: String) : Factory.Spec
}

它对我来说看起来非常有效,但如果没有关于您的业务的详细信息,就无法解决您的难题。为什么你认为你需要通用?

答案 1 :(得分:0)

实际上有一种类型可以安全地用于???var factory: Factory<*>。唯一的小问题是,您无法将任何内容传递给create(或者更确切地说,您只能传递Nothing)。

这是因为安全代码不允许

  

如果使用接受Spec的工厂然后传递另一个工厂,则在运行时崩溃。

如果你想要它,你需要在某个地方进行不安全的施放或在某个地方投掷,而应该&#34;看起来很丑陋而且看起来是错误的&#34;。

这有点好,因为它提供了一个有用的例外:

inline fun <reified T : Factory.Spec> Factory<T>.upcast(): Factory<Factory.Spec> = 
    object : Factory<Factory.Spec> {
        override fun create(spec: Factory.Spec): A = 
            if (spec is T) 
                this.create(spec) 
            else throw IllegalArgumentException("Bad spec type, need ${T::class}")
    }

var factory: Factory<Factory.Spec> = DefaultFactory().upcast()

如果create返回A?,则可以使其安全;只是因为这个原因,不要让它返回A?