Наблюдаемое свойство, позволяющее добавлять наблюдателей во время выполнения

Через Delegates.observable , Котлин допускает наблюдаемые свойства. Однако мне нужна возможность добавления наблюдателей во время выполнения, как это делает класс Observable Java.

Теперь у меня есть следующее:

 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 не заставляет вас реализовывать какой-либо интерфейс для поддержки делегированных свойств , yon может использовать делегированные свойства в Kotlin, просто предоставляя getValue & setValue (?) Операторам. и их видимость даже может быть частной .

Kotlin предоставил функцию operatorDelegate с 1.1, что позволяет вам управлять / управлять созданием делегата.

Делегат в Котлине работает в фоновом режиме , что означает, что он невидим с точки зрения исходного кода, и пусть источник кода рассматривает делегированные свойства как обычные свойства.

Делегированные свойства Kotlin могут легко позволить вам управлять java beans без использования PropertyEditorSupport в Java, и вам не нужно вообще управлять делегатом в 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 закрыты ниже.

 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) } }