kotlin属性代理

kotlin属性代理官方文档地址:http://kotlinlang.org/docs/reference/delegated-properties.html

kotlin的代理模式需要实现一个接口,而属性代理只需要实现getValue和setValue方法即可。

语法形式:val/var : by
其中代理了 的getValue和setValue方法。

一.自定义属性代理

举个:

class Example {
    var p: String by Delegate()
}
class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me!"
    }
 
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name}' in $thisRef.")
    }
}
fun main(args: Array) {
    val e = Example()
    println(e.p)
}

输出:Example@33a17727, thank you for delegating ‘p’ to me!

当我们给p赋值的时候,setValue会被调用

e.p = "NEW"

输出:NEW has been assigned to ‘p’ in Example@33a17727.

自定义属性代理也可以实现ReadWriteProperty、ReadOnlyProperty接口。

public interface ReadOnlyProperty {
    /**
     * 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
}

/**
 * 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 {
    /**
     * 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)
}

二.lazy

当变量第一次被使用时才进行初始化,可以实现懒加载。

lazy方法返回一个Lazy对象,入参是一个lambda。

public fun  lazy(initializer: () -> T): Lazy = SynchronizedLazyImpl(initializer)

当第一次获取lazyValue的值时,会先初始化lazyValue,然后把值保存起来,下一次获取lazyValue时直接获取保存好的值即可。

val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}

fun main(args: Array) {
    println(lazyValue)
    println(lazyValue)
}

输出:

computed!
Hello
Hello

初始化lazyValue的过程默认是线程安全的,通过synchronized锁来保证。

不过这肯定是影响性能的,如果我们确信lazyValue的初始化不会涉及到多线程,那么我们可以传入LazyThreadSafetyMode.NONE来取消同步锁。

val lazyValue: String by lazy(LazyThreadSafetyMode.NONE) {
    println("computed!")
    "Hello"
}

LazyThreadSafetyMode有三种模式:SYNCHRONIZED(默认模式)、PUBLICATION、NONE

其中PUBLICATION模式使用了AtomicReferenceFieldUpdater(原子操作)允许多个线程同时调用初始化流程。

三.observable

变量被赋值时会发出通知。
Delegates.observable可以传入两个参数,一个是初始值,另一个是变量被赋值时的handle方法。

import kotlin.properties.Delegates

class User {
    var name: String by Delegates.observable("") {
        prop, old, new ->
        println("$old -> $new")
    }
}

fun main(args: Array) {
    val user = User()
    user.name = "first"
    user.name = "second"
}

输出:

 -> first
first -> second

注意:只要 user.name被赋值,监听事件就会触发。

类似的还有 vetoable(),只不过vetoable是在赋值前触发,observable是在赋值后触发。

vetoable还可以对赋值操作进行拦截。

import kotlin.properties.Delegates

class User {
    var name: String by Delegates.vetoable("") { p, oldValue, newValue ->
        if (newValue == "first"){
            return@vetoable true // 返回true表示first可以赋值给name
        }
        return@vetoable false // 返回false表示拦截其他赋值操作。
    }
}

fun main(args: Array) {
    val user = User()
    user.name = "first"
    println(user.name)
    user.name = "two"
    println(user.name)
}

输出:

first
first

四.对map的代理

把map中某个key值映射为变量。

fun main(args: Array) {
    val map = mutableMapOf("name" to "小明", "age" to 1)
    var name: String by map
    println(name)
    name = "小红"
    println(map["name"])
}

输出:

小明
小红

五.局部变量的代理(1.1版本新增)

fun example(computeFoo: () -> Foo) {
    val memoizedFoo by lazy(computeFoo)

    if (someCondition && memoizedFoo.isValid()) {
        memoizedFoo.doSomething()
    }
}

六.提供代理(1.1版本新增)

我们可以干预代理类的创建过程。提供provideDelegate方法即可,该方法返回要创建的代理对象。

class ResourceDelegate : ReadOnlyProperty {
    override fun getValue(thisRef: MyUI, property: KProperty<*>): T { ... }
}
    
class ResourceLoader(id: ResourceID) {
    operator fun provideDelegate(
            thisRef: MyUI,
            prop: KProperty<*>
    ): ReadOnlyProperty {
        checkProperty(thisRef, prop.name)
        // create delegate
        return ResourceDelegate()
    }

    private fun checkProperty(thisRef: MyUI, name: String) { ... }
}

class MyUI {
    fun  bindResource(id: ResourceID): ResourceLoader { ... }

    val image by bindResource(ResourceID.image_id)
    val text by bindResource(ResourceID.text_id)
}

provideDelegate方法有两个参数,参数1是代理属性所在的类,即image所在的类:MyUI。参数2是代理属性的具体参数对像(包括属性名称,属性类型等等)。

你可能感兴趣的:(kotlin属性代理)