Kotlin专题「二十一」:委托和委托属性详解

本文详细介绍了Kotlin的委托模式和属性委托。委托模式允许对象组合实现代码复用,类委托可将方法实现委托给其他对象。属性委托包括延迟、观察、Map委托等类型,还介绍了其底层原理、规则。此外,还提及标准委托、本地委托、属性间委托及提供委托等内容。

前言:遇到困难时不要抱怨,既然改变不了过去,那么就努力改变未来。

一、概述

  有两个对象参与处理同一个请求,接收请求的对象将请求委托给另一个对象来处理,这就是委托。Kotlin直接支持委托模式,更优雅简洁,通过关键字 by 实现委托。

委托模式已经被证实是实现继承的一个很好替代方式,在扩展一个基类并重写方法时,基类就必须依赖子类的实现,当不断修改的时候,基类就会失去当初的性质,Kotlin 中就将类默认为 final,确保不会被修改。

有一种模式是装饰器模式,本质就是创建一个新类,实现与基类一样的接口,并且将类的实现作为一个子段保存,这样就能在基类不被修改的情况下直接修改基类的实例。但是缺点是造成很多样板代码。

    class CustomList<T>(val innerList: Collection<T> = mutableListOf<T>()) : Collection<T> {
   
   
        override val size: Int = innerList.size

        override fun contains(element: T): Boolean = innerList.contains(element)

        override fun containsAll(elements: Collection<T>): Boolean = innerList.containsAll(elements)
        
        override fun isEmpty(): Boolean = innerList.isEmpty()
        
        override fun iterator(): Iterator<T> = innerList.iterator()
    }

当你实现 Collection 接口的时候就需要重写上面的方法,代码量很多,但是如果用到委托的话代码就简单很多了。

    class DelegatingCollection<T>(val innerList: Collection<T> = mutableListOf<T>()) : Collection<T> by innerList {
   
   
        override fun isEmpty(): Boolean {
   
   //重写isEmpty()方法
            return innerList.isEmpty()
        }
    }

类 DelegatingCollection 继承 Collection<T> 的所有接口,利用 by 关键字将新类 DelegatingCollection 接口的实现委托给原始类 innerList: Collection<T>,编译器会为新类自动生成接口方法,并默认返回原始类的具体实现。当然我们也可以根据自己的需要重写对应的方法。

委托模式

Kotlin 支持委托模式, 是允许对象组合实现与继承相同的代码复用,简单来说就是操作的对象不用自己去执行,而是将任务交给另一个对象去操作,这种模式叫委托模式,被操作的对象叫委托。

委托模式有两个对象参与处理同一请求,接受请求的对象将请求委托给另一个对象来处理。

二、类委托

类的委托即一个类中定义的方法实际是调用另一个类对象的方法来实现的。

以下实例中, 派生类 Derived 继承了接口 Base 的所有方法,并且委托一个传入的 Base 类的对象来执行这些方法。

    //接口
    interface Base {
   
   
        fun share()
    }

    //实现此接口的被委托的类
    class BaseIMPL : Base {
   
   
        override fun share() {
   
   
            println("BaseIMPL:实现Base接口被委托的类")
        }
    }

    //通过关键字 by 创建委托类
    class Derived(b: Base) : Base by b

    fun main(args: Array<String>) {
   
   
		val baseImpl = BaseImpl()
        Derived(baseImpl).share()
    }

打印数据如下:

BaseIMPL:实现Base接口被委托的类

Derived 类中实现 Base 接口的方法委托给另一个对象 b: Base 来处理。

在 Derived 声明中,by 字句表示:将 b 保存在 Derived 的对象实例内部,而且编译器会让 Derived 生成继承自 Base 接口的所有方法,并将调用转发给 b。

上面的例子中,我们已经委托到一个对象了,如果要修改接口里面的方法的时候,可以直接重写,而不需要重新去写新的方法。

    //通过关键字 by 创建委托类
    class Derived(b: Base) : Base by b {
   
   
        override fun share() {
   
   //重写接口的方法
            println("Derived:委托类重写Base中的方法")
        }
    }

打印数据如下:

Derived:委托类重写Base中的方法

三、属性委托

属性委托是指一个类的某个属性值不是在类中直接定义的,而是将其托付给一个代理类,从而实现对该类的属性的统一管理。有一些常见的属性类型,尽管我们可以在每次需要时手动实现它们,但最好是只实现一次,放入库中一直使用。

属性委托包括:

  • 延迟属性(lazy properties):数据只在第一次访问时计算;
  • 观察属性(observable properties):监听器会得到这个属性变化的通知;
  • Map 委托属性(Storing Properties in a Map):把多个属性值存储在一个 Map 中,而不是为每个属性存储单独的字段。

委托的语法格式:

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

val/var <property name>: <Type> by <expression>
  • val/var :  属性类型;
  • 属性名 :  属性名称;
  • 类型 :   属性的数据类型;
  • 表达式 :  委托代理类。

3.1 委托的底层原理

在底层,Kotlin 编译器会为每个委托属性生成一个辅助属性并委托给它。

    class Person {
   
   
        var prop: Int by Delegate()
    }

对于属性prop,会生成隐藏属性 prop$delegate,访问器的代码会简单地委托给这个附加的属性:


                
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值