kotlin 委托

委托属性

特点:常见的属性类型,交给委托类统一实现,避免每个类都要单独重复实现一次

语法: val/var <属性名>: <类型> by <表达式>

by后面的表达式是委托,会被委托给它用operator修饰的getValue()函数 (于setValue()函数 ->对应于var属性)

属性委托要求

val声明的,委托必须提供一个名为getValue的函数,接收参数:

  • thisRef 必须与属性所有者类型相同或超类型(对应扩展函数指被扩展类型)
  • property 必须是类型KProperty<*>

var声明的, 还必须提供一个setValue函数

  • thisRef
  • property
  • newValue 必须与属性同类型或者它的子类型

委托类可以实现包含operator方法的 ReadOnlyProperty 或 ReadWriteProperty 接口之一

interface ReadOnlyProperty<in R, out T> {
    operator fun getValue(thisRef: R, property: KProperty<*>): T
}

interface ReadWriteProperty<in R, T> {
    operator fun getValue(thisRef: R, property: KProperty<*>): T
    operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}

kotlin标注库提供的委托

  1. 延迟属性的lazy

    lazy接收一个lambda 并返回Lazy实例函数。第一调用get() 执行lambda,并记录结果,后续get()返回记录的结果。

    lazy属性求值默认是同步锁的(synchronized) ,只在一个线程中计算,所有线程会看到相同的值。还有其它莫斯
    LazyThreadSafetyMode.PUBLICATION 和 LazyThreadSafetyMode.NONE

 val lazyValue: String by lazy{
     ....
     return "string"
 }

  1. 可观察属性Observable

Delegates.observable() 接收两个参数:初始值和修改是处理程序。每当给属性赋值后回执处理程序

处理程序有三个参数: 被赋值的属性,旧值,新值

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

  1. 把属性存储在映射中

映射map里存储属性的值(字符串key <—> 属性的名称)

class User(val map: Map<String,Any?>){
    val name: String by map
    val age: Int by map
}

val user - User(mapOf{
    "name" to "xxxx"
    "age"  to 20
})


  1. 局部委托属性

将局部变量声明为委托属性, 减少不必要的计算

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

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

提供自定义委托

通过定义provideDelegate操作符, 扩展创建属性实现所委托的对象逻辑。

如果by右侧使用的对象将 provideDelegate定义为成员函数或扩展函数,那么会调用该函数来创建委托实例。

class DuplicateDataFragment : BaseRxFragment(){
   val duplicateDatas: DuplicateCheckDatas by bindArgument("duplicateDatas")
   
       companion object {
     
        fun newInstance(duplicateDatas: DuplicateCheckDatas): DuplicateDataFragment {

            val fragment = DuplicateDataFragment()
            val bundle = Bundle()
            bundle.putSerializable("duplicateDatas", duplicateDatas)
            fragment.arguments = bundle
            return fragment
        }
    }
   
}

在xxx.kt文件中看bindArgument实现

fun<U,T> Activity.bindExtra(key: String) = BindLoader<U,T>(key)

fun <U, T> Fragment.bindArgument(key: String) = BindLoader<U, T>(key)

fun <U, T> android.app.Fragment.bindArgument(key: String) = BindLoader<U, T>(key)

class BindLoader<in U, out T>(private val key: String){
    operator fun provideDelegate(thisRef:U, prop: KProperty<*>): ReadOnlyProperty<U,T>{
        // 创建委托
        return IntentDelegate(key)
    }
}

private class IntentDelegate<in U, out T>(private val key: String): ReadOnlyProperty<U,T>{
    override fun getValue(thisRef: U, property: KProperty<*>): T {

        return when(thisRef){
            is Fragment -> thisRef.arguments?.get(key) as T
            is android.app.Fragment -> thisRef.arguments?.get(key) as T
            else -> (thisRef as Activity).intent?.extras?.get(key) as T
        }
    }

}


类委托

两个对象参与处理同一个请求,接受请求的对象将请求委托给另外一个对象来处理。是实现继承的一种替代方式。

kotlin可以零样板代码地原生支持。

class Derived(b: Base) : Base by b

by字句表示b将会在Derived中内部存储,并且编译器将生成转发给b的所有Base的方法。

覆盖由委托实现的接口成员

interface Base{
    fun printMessage()
}

class BaseImpl(val x: Int): Base{
    override fun printMessage(){
        print(x)
    }
}

class Dervied(b: Base): Base by b{
    override fun printMessage(){
        print("abc")
    }
}

编译器会使用override覆盖实现而不是委托对象中的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值