Kotlin专题禅与计算机程序设计艺术Kotlin编程

29. 委托属性

2017-11-24  本文已影响26人  厚土火焱

很多常见属性不是简单的数据,需要每次去手动实现。如果为了方便,可以只写一个类,把他们放进去反复使用是最好的选择。
这里我们使用委托属性。
先看一个例子

class Delegate{
    val Hello by lazy{
        "HelloWorld"
    }
}

当我们调用这个 Hello 的时候,会返回一个字符串 HelloWorld。这个 Hello 只会在第一次调用的时候才赋值。它是使用了 lazy 来实现这个延迟的操作。而观察 lazy 的源码,我们能发现,它有一个 getValue 的函数。

public inline operator fun <T> Lazy<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value

所以 lazy 能够实现取值。
调用方式如下

    val delegate = Delegate()
    println(delegate.Hello)

而这样的委托,我们也可以自己写出来。

class X {
    private var value:String? = ""
    operator fun getValue(thisRef: Any?, property: KProperty<*>):String{
        println("getValue: $thisRef -> ${property.name}")
        return value?:""
    }
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value:String){
        println("getValue: $thisRef -> ${property.name} = $value")
        this.value = value
    }

}

我们建立了一个类,叫 X。实现取值和赋值的操作。
为了看到细节,在赋值和取值的操作代码中,都加入了打印语句。
代码结构是不是很熟悉,是的,我是从 lazy 中抄过来的。不过,X 只支持 String 类型的读写。
然后,在类 Delegate 中增加两个属性。

    val Hello2 by X()
    var Hello3 by X()

一个常量、一个变量。
常量 Hello2 只能 getValue;变量 Hello3 可以getValue和setValue。
在 main 中我们直接输出,并且在给 Hello3 赋值,看看会发生什么。

    val delegate = Delegate()
    println(delegate.Hello)
    println(delegate.Hello2)
    println(delegate.Hello3)
    delegate.Hello3 = "顺"

这是完整的运行结果

HelloWorld
getValue: com.cofox.kotlin.Delegate@6ce253f1 -> Hello2

getValue: com.cofox.kotlin.Delegate@6ce253f1 -> Hello3

getValue: com.cofox.kotlin.Delegate@6ce253f1 -> Hello3 = 顺

尤其注意 Hello3,取值和赋值执行的是不同的函数方法。
由此可看出,虽然 delegate 的属性是 Hello2 Hello3,但是真正替代它们起作用的是 X。它的核心实现就是 getValue 和 setValue。

上一篇下一篇

猜你喜欢

热点阅读