kotlin类委托、属性委托

1.类委托

(1)概念

​ 本类需要实现的方法/属性,借用其他已实现该方法/属性的对象作为自己的实现;

​ 一旦使用了某类作为委托类,该类就能借用该委托类实现的方法/属性。

(2)定义

/**
 * 定义一个生物接口,有一个run抽象方法和一个抽象属性
 */
interface Creature {
    fun run()
    val type: String
}

/**
 * 定义一个委托类,实现了Creature接口
 */
class DelegateClass : Creature {
    override val type: String
        get() = "委托类该属性"

    override fun run() {
        println("代理类执行run方法")
    }
}

①委托类作为构造器形参传入(常用)

/**
 * 定义一个Human类,实现了Creature接口,委托类作为形参传入,由形参委托类对象作为委托对象
 */
class Human(delegateClass: DelegateClass) : Creature by delegateClass

②新建委托类对象

/**
 * 定义一个Dog类,实现了Creature接口,新建一个委托类作为委托对象
 */
class Dog : Creature by DelegateClass()

③新建委托类对象,并自己实现方法/属性

/**
 * 定义一个pig类,实现了Creature接口,新建一个委托类作为委托对象,并自己实现了抽象方法
 */
class Pig : Creature by DelegateClass() {
    override fun run() {
        println("自己执行实现的run方法")
    }

    override val type: String
        get() = "自己实现的type属性"
}

调用示例:

fun main(args: Array<String>) {
    //作为形参(委托对象可复用)
    val delegateClass = DelegateClass()
    val human = Human(delegateClass)
    human.run()//结果:代理类执行run方法
    println(human.type)//结果:委托类该属性
    val human2 = Human(delegateClass)
    human2.run()//结果:代理类执行run方法
    println(human2.type)//结果:委托类该属性

    //新建对象
    val dog = Dog()
    dog.run()//结果:代理类执行run方法
    println(dog.type)//结果:委托类该属性

    //新建对象并自己实现方法/属性
    val pig = Pig()
    pig.run()//结果:自己执行实现的run方法
    println(pig.type)//结果:自己实现的type属性
}

2.属性委托

(1)概念

​ 多个类的类似属性交给委托类统一实现,避免每个类都要单独重复实现一次。

(2)定义

/**
 * 定义一个委托类Jobs,
 * 为属性name创建了operator修饰的getValue和setValue方法
 * 该属性可被其他了委托该类共享
 */
class Jobs {
    var name: String = "工作名"
    operator fun setValue(thisRef: SoftWareDev, property: KProperty<*>, value: String) {
        this.name = value
    }

    operator fun getValue(thisRef: SoftWareDev, property: KProperty<*>): String {
        return this.name
    }
}

/**
 * 定义一个接口
 */
interface SoftWareDev

/**
 * 定义一个AndroidDev类,实现SoftWareDev接口
 * 属性name委托Jobs类实现
 */
class AndroidDev : SoftWareDev {
    var name: String by Jobs()
}

/**
 * 定义一个PhpDev类,实现了SoftWareDev接口
 * 属性name委托Jobs类实现
 */
class PhpDev : SoftWareDev {
    var name: String by Jobs()
}

/**
 * 定义一个类实现了SoftWareDev接口
 */
class ExtensionClass : SoftWareDev

/**
 * 为ExtensionClass扩展属性,该属性由委托类Jobs实现
 */
val ExtensionClass.name by Jobs()

fun main(args: Array<String>) {
    val androidDev = AndroidDev()
    androidDev.name = "android开发"
    println(androidDev.name)//结果:android开发
    val phpDev = PhpDev()
    println(phpDev.name)//结果:工作名
    println(ExtensionClass().name)//结果:工作名
}

(3)关于委托类的委托属性的getValue、setValue形参说明

①getValue(thisRef, property)

  • thisRef:代表委托属性所属对象,因此thisDef类型需要与委托属性所属对象类型一致,或者是其父类,如上面代码thisRef类型为SoftWareDev,是AndroidDev和PhpDev两个类的父类类型

  • property:代表目标属性,该属性必须是KProperty<*>类型或其父类类型

  • 返回值:返回目标属性相同的类型,或者其子类类型

②setValue(thisRef, property, value)

  • thisRef:同上;

  • property:同上;

  • value:为目标属性设置的新的值,因此该值类型必须与目标属性类型一致,或者是其父类

总结:传入形参类型需与目标类型一致或者是其父类类型,返回值类型需与目标类型一致或者是其子类类型。

(4)关于ReadOnlyProperty和ReadWriteProperty接口

  • ReadOnlyProperty接口定义了getValue方法;
  • ReadWriteProperty接口定义了getValue、setValue方法。

因此,委托类可以实现ReadOnlyProperty(val声明待委托属性时)或者ReadWriteProperty(var声明待委托属性时)接口来进行委托属性的定义。

上面Jobs类完全可以这么实现:

/**
 * 定义一个委托类Jobs,
 * 实现了ReadWriteProperty接口,重写setValue、getValue方法
 * 该属性可被其他了委托该类共享
 */
class Jobs : ReadWriteProperty<SoftWareDev,String>{
    var name: String = "工作名"
    override operator fun setValue(thisRef: SoftWareDev, property: KProperty<*>, value: String) {
        this.name = value
    }

    override operator fun getValue(thisRef: SoftWareDev, property: KProperty<*>): String {
        return this.name
    }
}
posted @ 2019-06-10 16:28  谢光伟  阅读(3769)  评论(0编辑  收藏  举报