【2025最新版Kotlin教程】Kotlin第一行代码系列第九课-委托

189 阅读4分钟
【2025最新版Kotlin教程】Kotlin第一行代码系列第九课-委托

委托功能很强大的,但由于有一点学习难度以及不是很清晰的使用场景,常常被忽略

经验总结:你可以给任何东西委托,没有限制。

一、委托类:
// 源码联系:893151960
interface WalkListener {
    fun walk()
}
class Chicken : WalkListener {
    override fun walk() {
        println("鸡用2只脚走路")
    }
}
class Panda : WalkListener {
    override fun walk() {
        println("熊猫用4只脚走路")
    }
}

使用示例:

/**
 * @author :congge
 * @date : 2023-02-03 9:58
 * @desc : 委托给walkListener对象了,就不用实现WalkListener接口方法了
 **/
// 方式1: 委托给传入的对象
class Animal(walkListener1: WalkListener):WalkListener by walkListener1 {

}

// 方式2:固定委托给了Chicken
class Anima2:WalkListener by Chicken() {

}

fun main() {
    Animal(Chicken()).walk()
    Animal(Panda()).walk()
}
二、属性代理:
fun main() {
    //====================================== 委托属性start ============================================
    // 方式1:最简单的委托属性 写法直接用 by ::xx
    //        即值全部委托给后面的属性,后面的属性值改变,它就会跟着改变
    // 它要在类中才能这样委托属性,所以建了一个Test
    class Test{
        var count = 100
        //它们会互相影响
        var total by ::count

        fun printTotal(){
            count = 101
            println(total)
            total = 102
            println(count)
        }
    }
    Test().printTotal()

    // 方式2:用委托来对属性进行延迟初始化,写法 by lazy {}
    // 只会在第一次调用才初始化,然后后面再调用就会直接用第一次初始化好的值
    /**
     * 注意:它有点讲究,就是变量只能用val,不能用var。
     *       这也给你更知道它的使用场景,就是你平常的val变量,是否能用lazy懒加载
     * 在Android开发中,View的声明就可以用这种方式
     * 如private val tvName: TextView by lazy{ findViewById(R.id.tv_name) }
     */
    val lazyValue :String by lazy {
        println("computed!")
        "Hello"
    }
    println(lazyValue)

    // 方式3:类似于方式2,也是对属性延后初始化 写法 var前加 lateinit
    /**
     * 使用场景比较明确,我知道这个变量不可能为null,且我后面再初始化它,它的值可以不断改变
     * 不像方式2,初始化一次后,值就改不了的
     */
    // 因为isInitialized只能在类内调用,所以建个Test2
    class Test2{
        lateinit var lazyValue1:String

        fun printLazyValue1(){
            lazyValue1 = "123"
            lazyValue1 = "456"
            println(lazyValue1)
            // 如果你怕没有初始化可以用isInitialized进行判断再使用
            if (::lazyValue1.isInitialized){
                println(lazyValue1)
            }
        }
    }
    Test2().printLazyValue1()

    /**
     * 选学,使用场景不多
     */
    // 方式4:用by Delegates.observable 来监听设置前后两个值变化
    var name: String by Delegates.observable("小象") {
            prop, old, new ->
        // 往往这里如果前后两个值不一样做一些逻辑,比如内容改变了,TextView控件才改变颜色
        println("$old -> $new")
    }
    name = "小红象"
    println(name)

    // 方式5:看MapDemo文件

    /**
     * 选学,高级用法自定义委托,其实要想真正用上委托,它是必须学的
     */
    // 为什么要自定义委托,比如下面param属性,它set时会自定帮我去掉空格
    // 假设我要其他字符串也要这样的功能呢,你不会每个属性都写个这样的代码吧,这时自定义委托就派上用场了
    class Example {
        var param: String = ""
            set(value) {
                field = value.trim()
            }
    }

    // 方式6:我们自定义委托,需求场景就是统一我要在get和set前加写我们的逻辑
    // 通过by使用属性代理的方式,记得固定格式
    var str : String by PropertyDelegate("我是代理类")
    println(str)
    str = "haha  "
    println(str)
    // 忘了固定格式,看PropertyDelegate1类 可以实现ReadWriteProperty接口
    var str1 : String by PropertyDelegate1("我是代理类")
    println(str1)
    str1 = "haha233"
    println(str1)

    // 方式7:如果想在自定义委托前修改或者加些判断
    /**
     * 这个很少用到,可忽略
     */
    var str2:String by PropertyBeforeDelegate()
    str2 = "haha999"
    println(str2)

    /**
     * 使用场景1 :类的外部可以访问它的值,但不允许类的外部修改它的值
     * 它叫做:属性可见性封装
     */
    // 外部只能访问data值,不能修改它,因为List<String>没有add和remove方法
    class SimpleTest {
        val data: List<String> by ::_data
        private val _data: MutableList<String> = mutableListOf()

        fun load() {
            _data.add("委托1")
        }
    }

    /**
     * 使用场景2:Android开发中adapter其实很适合用by lazy {}
     */


    //====================================== 委托属性end ============================================


}
整个kotlin教程项目源码结构图:

在这里插入图片描述
有问题或者完整源码的可以看简介联系我,也可以私信我,我每天都看私信的