通过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
}
它有效,但感觉就像重新发明轮子一样。
对此没有标准解决方案吗?
如果没有,我的做法是否正确?
答案 0 :(得分:1)
相同想法的略微变化:
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
属性设为私有,并添加一个添加订阅者的方法,但为了简单起见我省略了它。
答案 1 :(得分:0)
这是因为你从一个简单的例子开始,并且无法找到Kotlin delegated properties的好处。
Kotlin并没有强迫您实现任何支持delegated properties的界面,您可以在Kotlin中使用delegated properties只提供getValue & setValue(?)运算符。他们的知名度甚至可以是私人。
Kotlin自1.1以来提供了provideDelegate运算符功能,可让您管理/控制如何来创建委托。
Kotlin中的代表正在使用后台,这意味着从源代码的角度来看它是不可见,让代码源处理{{3作为常规属性。
Kotlin delegated properties可以轻松地让您在不使用Java中的delegated properties的情况下管理java bean,并且您根本不需要在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">]}
注意:PropertyEditorSupport运算符功能私有。
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)
}
}