Android开发Kotlin编程Kotlin代码日记

什么,属性也能有观察者模式?

2019-04-07  本文已影响2人  小小小小小粽子

在前面的博文中,我们一起探究了类代理代理属性,一起深入了解了它们的实现机制,顺便还讨论了下标准库的玩儿法: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方法,所以该方法一直返回trueafterChange在这里一定会被调用。

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时,会停止方法的执行,也就不会赋值了。

这波分析下来,是不是如醍醐灌顶!普通的代理属性加上一些封装却有了类似于观察者模式响应变化的能力。我们也是知道如何实现一个代理属性的,却不一定能做出这样的操作,所以大家还是有时间多读读标准库的源码,总有一些独特的编码示范。

上一篇 下一篇

猜你喜欢

热点阅读