Observable属性允许在运行时添加观察者

通过Delegates.observable ,Kotlin允许可观察的属性。 但是,我需要在运行时添加观察者的能力,就像Java的Observable类一样。

我现在拥有的是:

 import java.util.* import kotlin.reflect.KProperty import kotlin.reflect.KProperty0 import kotlin.reflect.jvm.isAccessible class MyObservable<T> (var v: T): java.util.Observable() { operator fun getValue(thisRef: Any, prop: KProperty<*>) = v operator fun setValue(thisRef: Any, prop: KProperty<*>, newValue: T) { v = newValue setChanged() notifyObservers() } } fun <T> addObserver(prop: KProperty0<T>, observerFn: (T) -> Unit) = (prop.apply{ isAccessible = true }.getDelegate() as MyObservable<T>) .addObserver(Observer({ o, _ -> observerFn((o as MyObservable<T>).v) })) class ObservableExample { var i: Int by MyObservable(3) } fun main(args: Array<String>) { val ex: ObservableExample = ObservableExample(); addObserver(ex::i, { println(it) }) ex.i = 7 ex.i = 9 // prints: // 7 // 9 } 

它的工作,但感觉就像重新发明轮子。

这是不是有一个标准的解决方案?

如果不是,我所做的是正确的?

同样的想法稍微短一点的变种:

 import kotlin.properties.Delegates typealias IntObserver = (Int) -> Unit class ObservableExample { val prop1Observers = mutableListOf<IntObserver>() var prop1: Int by Delegates.observable(0) { prop, old, new -> prop1Observers.forEach { it(new) } } } fun main(args: Array<String>) { val example = ObservableExample() example.prop1Observers.add({ println(it) }) example.prop1 = 1 example.prop1 = 2 } 

产量如预期。 也许,最好是将observers属性设为私有,并添加一个添加订阅者的方法,但是为了简单,我省略了它。

这是因为你从一个简单的例子开始,并且找不到Kotlin 委托属性的好处。

Kotlin不会强迫你实现任何支持委托属性的接口,你可以使用Kotlin中的委托属性来提供getValue和setValue(?)操作符。 他们的知名度甚至可以是私人的

Kotlin从1.1开始提供了一个provideDelegate运算符函数,可以让您管理/控制如何创建委托。

Kotlin中的代理正在后台工作,这意味着从源代码的角度它是不可见的,并让代码源将委托属性视为常规属性。

Kotlin 委派的属性可以很容易地让你管理Java Bean,而不需要在Java中使用PropertyEditorSupport ,而且你不需要在Kotlin中管理委托,只是为了通知更改后的属性。 例如:

 val history = mutableMapOf<String, MutableList<Pair<Any?, Any?>>>() val subject = Subject() subject.subscribe { event -> val each = history.getOrPut(event.propertyName) { mutableListOf() } each.add(event.oldValue to event.newValue) } // v--- treat a delegated property as regular property subject.number = 1 subject.string = "bar" subject.number = 2 println(history); // ^--- {"number":[<null,1>,<1,2>], "string": [<null,"bar">]} 

注意: getValue&setValue操作符在下面是private

 class Subject { // v--- manage the delegated property internally var string: String? by this var number: Int? by this private val properties by lazy { mutableMapOf<Any?, Any?>() } private val listeners by lazy { mutableListOf<PropertyChangeListener>() } private operator @Suppress("UNCHECKED_CAST") fun <T : Any?> getValue(self: Any, prop: KProperty<*>): T { return properties[prop.name] as T } private operator fun <T : Any?> setValue(self: Any,prop: KProperty<*>, newValue: T) { val event = PropertyChangeEvent( self, prop.name, properties[prop.name], newValue ) properties[prop.name] = newValue listeners.forEach { it.propertyChange(event) } } fun subscribe(listener: (event: PropertyChangeEvent) -> Unit) { subscribe(PropertyChangeListener { listener(it) }) } fun subscribe(subscriber: PropertyChangeListener) { listeners.add(subscriber) } }