什么,属性也能有观察者模式?
在前面的博文中,我们一起探究了类代理跟代理属性,一起深入了解了它们的实现机制,顺便还讨论了下标准库的玩儿法:lazy
函数,其实除了lazy
这种懒加载的函数,还有用代理属性实现类似观察者模式的机制,我们一起来看一下。
标准库给我们提供的是Delegates.observable
,它的使用方法如下:
fun main(args:Array<String>){
var name by Delegates.observable("王小明") { property, oldValue, newValue ->
println("$oldValue -> $newValue")
}
name="海东"
name="剑"
}
observable
函数很简单,第一个参数我们传入一个初始值,第二个参数我们传入一个lambda,可以对旧值新值做一些操作,每次赋值都会调用我们的lambda,我们这里在赋值的时候就会打印出旧值新值,事实上你可以在这里做你想做的任何操作。
很神奇又很简单,总让人好奇是怎么实现的:
public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
ReadWriteProperty<Any?, T> =
object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
}
我们看到这个方法返回了我们熟悉的ReadWriteProperty
接口的对象,实际上是个ObservableProperty
子类的对象,在这里重写了afterChange
方法,会转而调用我们传入的lambda。afterChange
方法的调用逻辑则放在ObservableProperty
类里面:
public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
private var value = initialValue
protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true
protected open fun afterChange(property: KProperty<*>, oldValue: T, newValue: T): Unit {}
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val oldValue = this.value
if (!beforeChange(property, oldValue, value)) {
return
}
this.value = value
afterChange(property, oldValue, value)
}
}
主要逻辑在setValue
方法里面,我们可以看到,在每次赋值完成之后,都会调用我们的afterChange
方法,注意在此之前我们有一个if判断,会终止方法的执行,不过由于我们这儿并没有重写beforeChange
方法,所以该方法一直返回true
,afterChange
在这里一定会被调用。
那beforeChange
有什么用呢,这就要说到我们的另一个方法了。
var maxLength: String by Delegates.vetoable("init value") { property, oldValue, newValue ->
newValue.length > oldValue.length }
这里的vetoble
方法只有在我们传入的lambda返回true
的时候才会执行赋值。
我们来看一下实现:
public inline fun <T> vetoable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean):
ReadWriteProperty<Any?, T> =
object : ObservableProperty<T>(initialValue) {
override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = onChange(property, oldValue, newValue)
}
哦哟,这里还是实现的相同的ObservableProperty
,这不过这次重写的是beforeChange
,也就是说,在这种情况下,调用setValue
的时候,我们有可能会不执行赋值操作。
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val oldValue = this.value
if (!beforeChange(property, oldValue, value)) {
return
}
this.value = value
afterChange(property, oldValue, value)
}
当我们传入的lambda返回false
时,会停止方法的执行,也就不会赋值了。
这波分析下来,是不是如醍醐灌顶!普通的代理属性加上一些封装却有了类似于观察者模式响应变化的能力。我们也是知道如何实现一个代理属性的,却不一定能做出这样的操作,所以大家还是有时间多读读标准库的源码,总有一些独特的编码示范。