【问题标题】:Initializing interface instance variables初始化接口实例变量
【发布时间】:2018-02-20 02:05:25
【问题描述】:

我想通过使用接口在 Kotlin 类中注入(丰富)行为和状态。像class Impl : Observable,其中 Observable 包含状态。

在 Scala 中使用 Traits(确实有效),为此寻找 Kotlin 解决方案:

object Test extends App {
  val impl = new Impl()
  val observer = new Observer()
  impl.register(observer)
}

trait Observable {
  // How to do this in Kotlin?
  val observers = List()

  def register(observer: Observer) {
    observers.add(observer)
  }
}
class Observer

class Parent
class Impl extends Parent with Observable

在 Kotlin 中的尝试(不工作):

fun main(args: Array<String>) {
    val impl = Impl()
    val observer = Observer()
    impl.register(observer)
}

interface Observable {
    // Error: Kotlin: Property initializers are not allowed in interfaces
    val observers = mutableListOf<Observer>()

    fun register(observer: Observer) {
        observers.add(observer)
    }
}
class Observer

open class Parent
class Impl : Parent(), Observable

导致接口实例变量行出现此错误:Kotlin: Property initializers are not allowed in interfaces。 如何在 Kotlin 接口中初始化实例变量? (请注意,在此设计中,不应更改/更新父类。)

更新:我有一个 Java 示例解决方案,但它的行为不正确。 Java 接口中的“实例变量”自动是静态的。所以我删除了那个例子。

【问题讨论】:

  • 如果您稍微转一下,这是可能的,我添加了一个答案,因为接受的答案不包括您实际可以做些什么来实现与您试图实现的相同目标。太快接受答案意味着您以后可能无法获得正确的答案。

标签: interface kotlin


【解决方案1】:

您可以在 Kotlin 接口中使用状态占位符,并让实现类提供该状态。因此,接口可以提供与预期存在状态相反的功能。如:

class Observer

interface Observable {
    val observers: MutableList<Observer> // not present, but expected

    fun register(observer: Observer) {
        observers.add(observer)
    }
}

open class Parent

class Impl : Parent(), Observable {
    override val observers = mutableListOf<Observer>() // used by the interface
}

这是有充分理由的,存在来自类层次结构中多个项目的状态的微妙问题,而 Kotlin 正在防止此类模型可能出现的问题。

【讨论】:

    【解决方案2】:

    在 Java 中,您实际上有一个静态字段,而不是实例字段(与 Scala 代码不同,它确实可以按您的预期工作):

    Every field declaration in the body of an interface is implicitly public, static, and final.

    您可以在 Kotlin 中通过将字段放入伴随对象中来实现相同的行为。

    但您实际上应该做的是使用abstract class 而不是接口。

    delegation:

    interface Observable {
        fun register(observer: Observer)
    }
    
    class ObserverList : Observable {
        val observers = mutableListOf<Observer>()
    
        override fun register(observer: Observer) {
            observers.add(observer)
        }
    }
    
    class Impl : Parent(), Observable by ObserverList()
    

    【讨论】:

    • 你说得对,Java 接口中的实例变量是静态的。我刚刚更新了我的帖子以反映这一点。但是抽象类不是一个选项,因为该类必须扩展另一个无法修改的类。所以我猜想他们在 Scala 中所说的“丰富”,在 Java 或 Kotlin 中是不可能的。
    • 丰富不能添加实例变量(扩展类不是“丰富”)。
    • @AlexeyRomanov 这并不能解决问题,并且允许接口支持针对它想要定义的状态的逻辑。在 Kotlin 中有一种方法可以做到这一点。
    猜你喜欢
    • 2017-04-05
    • 2011-03-18
    • 2010-11-26
    • 1970-01-01
    • 2014-09-14
    • 2013-07-04
    • 1970-01-01
    • 2012-09-17
    • 2013-08-14
    相关资源
    最近更新 更多