美文网首页
kotlin提供的一些属性代理

kotlin提供的一些属性代理

作者: qiHuang112 | 来源:发表于2020-03-12 14:26 被阅读0次

    前言

    在上一篇文章中降到了lazy{""}作为koltin的属性代理对象,在kotlin中,除了lazy还有一些其他的属性代理方式。

    关于by关键字

    还是先复习一下by关键字的使用方法
    val(r) [变量名] by [代理对象]
    EXP:val a by lazy{"huang"}
    也就是说,by之后跟的是一个对象,这是一个存在getValue方法的实例对象!
    如果能认识大这一点,那么by关键字就很简单了。直接来看看到底有哪些属性代理对象吧。

    属性代理对象们

    一共有三个,分别是下面三个

    • Delegates.notNull<T>
    • Delegates.observable<T>
    • Delegates.vetoable<T>

    先解释一下是干啥的,然后再告诉你为什么。

    • Delegates.notNull<T>表示属性不为空,如果为空,则抛出异常,相当于java版本的不给初始值的属性,默认为null
    • Delegates.observable<T>表示属性可观测,在设置值的前后提供监听方法,函数入参包含了初值,所以不为空,相当于给了初值并设置了监听
    • Delegates.vetoable<T>表示属性设置成功需要满足一定的条件,这个方法返回的对象是Delegates.observable<T>的一个子对象,可以一起分析

    整体看,这三个方法都返回一个ReadWriteProperty<in R, T>对象
    先看看这个对象的源码:

    **
     * Base interface that can be used for implementing property delegates of read-write properties.
     *
     * This is provided only for convenience; you don't have to extend this interface
     * as long as your property delegate has methods with the same signatures.
     *
     * @param R the type of object which owns the delegated property.
     * @param T the type of the property value.
     */
    public interface ReadWriteProperty<in R, T> {
        /**
         * Returns the value of the property for the given object.
         * @param thisRef the object for which the value is requested.
         * @param property the metadata for the property.
         * @return the property value.
         */
        public operator fun getValue(thisRef: R, property: KProperty<*>): T
    
        /**
         * Sets the value of the property for the given object.
         * @param thisRef the object for which the value is requested.
         * @param property the metadata for the property.
         * @param value the value to set.
         */
        public operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
    }
    

    你看,果然实现了getValue方法,并且同时实现了setValue方法,再看看注释,这个接口就是为了给可读写属性用作代理的,简直是不要太方便啊。

    看看这个接口的实现类

    • 1.NotNullVar
    private class NotNullVar<T : Any>() : ReadWriteProperty<Any?, T> {
        private var value: T? = null
    
        public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
            return value ?: throw IllegalStateException("Property ${property.name} should be initialized before get.")
        }
    
        public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
            this.value = value
        }
    }
    
    • 2.ObservableProperty
    /**
     * Implements the core logic of a property delegate for a read/write property that calls callback functions when changed.
     * @param initialValue the initial value of the property.
     */
    public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
        private var value = initialValue
    
        /**
         *  The callback which is called before a change to the property value is attempted.
         *  The value of the property hasn't been changed yet, when this callback is invoked.
         *  If the callback returns `true` the value of the property is being set to the new value,
         *  and if the callback returns `false` the new value is discarded and the property remains its old value.
         */
        protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true
    
        /**
         * The callback which is called after the change of the property is made. The value of the property
         * has already been changed when this callback is invoked.
         */
        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)
        }
    }
    

    在看看前面分析的kotlin提供的三种初始化方式,结构自然就出来了

    • Delegates.notNull<T> 对应 NotNullVar
    • Delegates.observable<T> 对应 ObservableProperty
    • Delegates.vetoable<T> 对应 ObservableProperty

    当然,我们也可以更直接一点,自己构造一个对象,继承ObservableProperty来完成我们自己特殊的需求

    var e by object : ObservableProperty<String>("hhhh") {
        override fun beforeChange(property: KProperty<*>, oldValue: String, newValue: String): Boolean {
            val flag = oldValue.length < newValue.length
            println("'$newValue'长度${if (flag) "大" else "小"}于'$oldValue', 修改${if (flag) "成功" else "失败"}!")
            return flag // 为false则允许修改
        }
        override fun afterChange(property: KProperty<*>, oldValue: String, newValue: String) {
            println("'$oldValue' 被修改为 '$newValue'!")
        }
    }
    

    下面提供我在学习的时候自己写的一个小demo,里面有一些例子,感兴趣的可以跑跑看,记得结合show kotlin bytecode,对照反编译的java代码食用更佳哦!

    package delegate
    
    import kotlin.properties.Delegates
    import kotlin.properties.ObservableProperty
    import kotlin.reflect.KProperty
    
    class M {
        val s: String by MyDelegate { "Hello" }
        var a by Delegates.notNull<String>()
        var b by Delegates.observable("b") { _: KProperty<*>, oldValue: String, newValue: String ->
            println("'$oldValue' has been changed by '$newValue'!")
        }
        var c by Delegates.vetoable("world") { _: KProperty<*>, oldValue: String, newValue: String ->
            oldValue.length < newValue.length
        }
        val d by lazy { "d" }
        var e by object : ObservableProperty<String>("hhhh") {
    
            override fun beforeChange(property: KProperty<*>, oldValue: String, newValue: String): Boolean {
                val flag = oldValue.length < newValue.length
                println("'$newValue'长度${if (flag) "大" else "小"}于'$oldValue', 修改${if (flag) "成功" else "失败"}!")
                return flag // 为false则允许修改
            }
    
            override fun afterChange(property: KProperty<*>, oldValue: String, newValue: String) {
                println("'$oldValue' 被修改为 '$newValue'!")
            }
        }
    }
    
    class MyDelegate<T>(val init: () -> T) {
        operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
            return init()
        }
    }
    
    fun main() {
        val m = M()
        println(m.s)
    //    println(m.a)
        println(m.b)
        println(m.c)
    
        m.e = "hh"
        m.e = "hhhhhh"
    
    }
    

    ***分割线****


    注意到getValue和setValue竟然是两个operator方法,那么它们是实现了哪个操作符呢?没错,就是等号=,怪不得kotlin不让我重载这个操作符,原来它被用在属性代理里了。
    目前kotlin还不支持直接点进去查看等号的具体实现,也就没有其他操作符那么方便的看源码了。不过想看的话,点到对应的属性,找熟悉的by关键字,然后看看by关键字后面的代理对象的实现就ok啦。

    相关文章

      网友评论

          本文标题:kotlin提供的一些属性代理

          本文链接:https://www.haomeiwen.com/subject/ofeujhtx.html