初始化接口实例变量

5
我希望通过使用接口在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接口中初始化实例变量? (请注意,在此设计中,父类不应被更改/更新。)

如果稍微改变一下,这是可能的,我添加了一个答案,因为被接受的答案并不能涵盖你实际想要实现相同目标所能做的。过快采纳答案可能意味着你以后无法吸引到正确的答案。 - Jayson Minard
2个回答

11

在 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 正在预防这种模型可能出现的问题。


3
在Java中,实际上你有一个静态字段,而不是实例字段(与Scala代码不同,它会按照你的预期工作):
每个接口体中的字段声明都隐含着public、static和final。
你可以通过将字段放入伴生对象中来实现在Kotlin中的相同行为。
但是你实际上应该使用抽象类而不是接口。
或者委托:
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接口中的实例变量是静态的说得对。我刚刚更新了我的帖子以反映这一点。但抽象类不是一个选项,因为该类必须扩展另一个无法修改的类。所以我猜在Java或Kotlin中不能像Scala中所谓的“enriching”那样实现。 - Devabc
扩展类并不能添加实例变量(扩展类并不等同于“丰富”)。 - Alexey Romanov
@AlexeyRomanov 这并不能解决问题,也不能让接口支持对其想要定义的状态进行逻辑操作。在 Kotlin 中有一种方法可以实现这一点。 - Jayson Minard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接