• Kotlin 委托


    定义

    有时候我们需要办成某件事但又不想自己做时,可以将其交给别人做,这其实就是一种委托。Kotlin 中可以使用by关键字声明委托。

    继承/实现的委托

    某个类ClassA想要实现一个接口MyInterface,但是发现接口中的抽象方法非常多,全部实现非常困难。巧的是我们已经有另一个类ClassB(或者该接口的一个对象)实现了该接口,此时我们可以将ClassA的实现MyInterface的工作委托给ClassB

    interface MyInterface {
        // 超多抽象方法
        fun example()
    }
    
    
    class ClassB: MyInterface {
        // 超多抽象方法的实现
        override fun example() = print("ClassB 实现")
    }
    
    
    class ClassA(classB: ClassB): MyInterface by classB {
        // ClassA 不需要自己实现 MyInterface 的方法
    }
    
    
    fun main() {
        val classB = ClassB()
        ClassA(classB).example()
    }
    
    ClassB 实现
    

    如果我们发现ClassB中的某个方法的实现并不是ClassA想要的,还可以在ClassA中声明对MyInterface方法的重写,此时如果调用ClassAexample则会调用新重写的这个:

    interface MyInterface {
        // 超多抽象方法
        fun example()
    }
    
    
    class ClassB: MyInterface {
        // 超多抽象方法的实现
        override fun example() = print("ClassB 实现")
    }
    
    
    class ClassA(classB: ClassB): MyInterface by classB {
        override fun example() = print("ClassA 实现")
    }
    
    
    fun main() {
        val classB = ClassB()
        ClassA(classB).example()
    }
    
    ClassA 实现
    

    属性的委托

    委托给对象

    我们可以将属性 getter 和 setter 委托给某一个对象,此时会将getset函数委托给类的getValuesetValue声明。

    val修饰的不可变变量只有 getter,因此只会将get委托给getValue

    最常见的是Lazy,我们可以使用函数lazy(后边的 lambda 需要返回一个值作为变量的初始值,该值的类型会作为变量类型)生成一个Lazy对象,并将某一个变量委托给它:

    val name = "Kotlin".also { println("name 初始化") }
    val lazyName by lazy { println("lazyName 初始化"); "Kotlin" }
    
    val version = 2.also { println("version 初始化") }
    val lazyVersion by lazy { println("lazyVersion 初始化"); 2 }
    
    fun main() {
        // 在运行时,name 就被初始化了
        // 而委托给 Lazy 的 lazyName 没有被初始化
    
        // 在运行时,version 就被初始化了
        // 只有在访问值时,lazyVersion 才会被初始化
        lazyVersion
    }
    
    name 初始化
    version 初始化
    lazyVersion 初始化
    
    

    委托给另一个变量

    此时委托变量前需要加双冒号::,事实上,::name会返回一个KMutableProperty0对象,所以这是还是将变量委托给了对象。比较特殊的是,该对象并没有声明getValuesetValue,委托将交给其 getter 和 setter。

    二者的 getter 和 setter 实际上已经绑定在一起了,当其中一个的值改变,另一个也会跟着变。

    var name: String = "K1"
    
    
    fun main() {
        var delegateName by ::name
        
        // 打印 name 并改变 delegateName 也是同样的结果
        println(delegateName)
        name = "K2"
        print(delegateName)
    }
    
    K1
    K2
    

    能将可变变量var委托给不可变变量val,因为val没有 setter。

    val name: String = "K1"
    
    
    fun main() {
        // 这是错误的
        // var delegateName by ::name
    }
    

    自定义可委托类

    得益于 IDEA 自动补全,我们可以直接写出委托关系var value by MyClass(),鼠标悬停(或者光标置于标红处,按键盘Alt+Enter),点击创建getValuesetValue,并加以修改即可。其中,参数名可以自定义。

    生成的nothing(第1个参数)一般是叫thisRef,它的类型是该变量所有者的类型(例如某个类的成员变量,其所有者是该类)。
    这里Nothing?则表示没有所有者。对于其他类型,如果加了?,则所有变量都可以委托,如果不加,则只有变量的所有者为指定类型可以委托。

    property中则包含了委托变量的属性,例如property.name可以获取到变量名。其类型必须为KProperty<*>

    getValue的返回值一般需要指明为所要获取值的类型,这里把MyClass.value返回。
    setValue传入的第3个参数则是要赋的值,这里把值给MyClass.value

    import kotlin.reflect.KProperty
    
    
    class MyClass {
        private var value = "MyClass"
    
    
        operator fun getValue(thisRef: Nothing?, property: KProperty<*>): String {
            println("getValue")
            return value
        }
    
    
        operator fun setValue(thisRef: Nothing?, property: KProperty<*>, s: String) {
            println("setValue")
            value = s
        }
    }
    
    
    fun main() {
        var value by MyClass()
        println(value)
        value = "Hello"
        print(value)
    }
    
    getValue
    MyClass
    setValue
    getValue
    Hello
    
  • 相关阅读:
    Spring底层原理学习笔记--第一讲--(BeanFactory与ApplicaitonContext)
    最佳精准度:解锁超级学习器和校准曲线的潜能
    网络基础概论
    PHP中流的理解
    工程代码实践简单总结
    解决服务器80端口无法连接的办法
    lua函数定义
    IEEE投稿模板下载
    自组织是管理者和成员的双向奔赴
    网络安全从业人员能力图谱
  • 原文地址:https://blog.csdn.net/weixin_67575670/article/details/139321073