nikolaymetchev
04/03/2017, 11:28 PMimport kotlin.properties.Delegates
import kotlin.reflect.KProperty
import kotlin.reflect.jvm.javaField
open class PropertyChangeAware {
private val changeListeners: MutableMap<String, MutableList<(KProperty<*>, Any, Any) -> Unit>> = mutableMapOf()
// can I use something more accurate than toString() here
private fun getChangeListeners(property: KProperty<*>) : MutableList<(KProperty<*>, Any, Any) -> Unit> {
require(property.javaField?.declaringClass == javaClass, {"The property $property doesn't belong to $javaClass" })
// Is there a way to check here if the property is for the same instance as this?
return changeListeners.computeIfAbsent(property.toString(), { mutableListOf() })
}
protected val observer: (KProperty<*>, Any, Any) -> Unit = { property, oldValue, newValue ->
getChangeListeners(property)
.forEach({ it.invoke(property, oldValue, newValue) })
}
fun <T : Any> addPropertyChangeListener(property: KProperty<T>, listener: (KProperty<T>, T, T) -> Unit) =
getChangeListeners(property)
.add(listener as (KProperty<*>, Any, Any) -> Unit)
}
class MyClass(prop1: String, prop2: Int) : PropertyChangeAware() {
var prop1: String by Delegates.observable(prop1, observer)
var prop2: Int by Delegates.observable(prop2, observer)
}
fun main(args: Array<String>) {
val myClass = MyClass("A", 3)
myClass.addPropertyChangeListener(myClass::prop1, listener())
myClass.addPropertyChangeListener(myClass::prop2, listener())
myClass.prop1 = "B"
myClass.prop2 = 10
}
private fun <T> listener(): (KProperty<T>, T, T) -> Unit = {
prop, old, new -> run {
println("$prop changed from $old to $new")
}
}