委托(Delegate)

1. 类的委托

委托模式 给实现继承提供了很好的代替方式, Kotlin 在语法上支持这一点,所以并
不需要什么样板代码。 Derived 类可以继承 Base 接口并且指定一个对象代理
它全部的公共方法:

//  类的委托
//  AOP(面向方面编程)
interface Base
{
    fun print()
}
class BaseImpl(val x:Int):Base
{
    override fun print() {
        println(x)
    }
}
class Child1(b:Base):Base by b
{
   fun getName():String
   {
       return "Bill"
   }
}
class Child2(b:Base):Base by b
{

}
class Child3(b:Base):Base by b
{

}
fun main(args: Array<String>)
{
    val b = BaseImpl(10)
    Child1(b).print()
    Child2(b).print()
    Child3(b).print()
}

在 Child1的父类列表中的 by 从句会将 b 存储在 Child1内部对象,并
且编译器会生成 Base 的所有方法并转给 b 。

2. 委托属性

很多常用属性,虽然我们可以在需要的时候手动实现它们,但更好的办法是一次实
现多次使用,并放到库。比如:

  • 延迟属性:只在第一次访问是计算它的值
  • 观察属性:监听者从这获取这个属性

更新的通知 在 map 中存储的属性,而不是单独存在分开的字段为了满足这些情形,Kotllin 支持代理属性:

class Example {
var p: String by Delegate()
}

语法结构是: val/var : by 在 by 后
面的属性就是代理,这样这个属性的 get() 和 set() 方法就代理给了它。
属性代理不需要任何接口的实现,但必须要提供 get() 方法(如果是变量还需要
set() 方法)。像这样:

class MyClass1
{
    //  将name属性委托给Delegate类
    var name:String by Delegate()
}
class MyClass2
{
    var name:String by Delegate()
}
//  属性委托类
class Delegate
{
    var name:String = ""
    operator fun getValue(thisRef:Any?, property:KProperty<*>):String
    {
        //  获取thisRef指定的类名
        val className = thisRef.toString().substringBefore('@')
        println("getValue被调用")
        println("${className}.get已经被调用")
        return name
    }
    operator fun setValue(thisRef:Any?, property:KProperty<*>,value:String)
    {
        //  获取thisRef指定的类名
        val className = thisRef.toString().substringBefore('@')
        println("setValue被调用")
        println("${className}.set已经被调用")
        name = value

    }
}
fun main(args: Array<String>)
{
    var c1 = MyClass1()
    var c2 = MyClass2()

    c1.name = "Bill"
    c2.name = "Mike"

    println(c1.name)
    println(c2.name)
}

输出:

这里写图片描述

委托属性的要求:

只读属性 (val),委托必须提供一个名字叫 get 的方法并接受如下参数:

  • 接收者–必须是相同的,或者是属性拥有者的子类型
  • 元数据–必须是 PropertyMetadata 或这它的子类型

这个函数必须返回同样的类型作为属性。
可变属性 (var),委托必须添加一个叫 set 的函数并接受如下参数:

  • 接受者–与 get() 一样 元数据–与 get() 一样
  • 新值–必须和属性类型一致 或是它的字类型

3.委托类的初始化函数

如果委托类有主构造器,也可以向主构造器传入一个初始化函数。这是可以定义一个委托函数的返回值是委托类,并在委托时指定初始化函数。

扫描二维码关注公众号,回复: 154448 查看本文章
import kotlin.reflect.KProperty

//  委托类的初始化函数

public fun <T> delegate(initializer:()->T):Delegate1<T> = Delegate1(initializer)
class MyClass11
{
    //  将name属性委托给delegate
    var name:String by delegate {
        println("MyClass1.name初始化函数调用")
        "<MyClass1>"
    }
}
class MyClass22
{
    var name:String by delegate {
        println("MyClass2.name初始化函数调用")
        "<MyClass2>"
    }
}
//  属性委托类
class Delegate1<T>(initializer:()->T)
{
    var name:String = ""
    var className = initializer()
    operator fun getValue(thisRef:Any?, property: KProperty<*>):String
    {

        println("getValue被调用")
        println("${className}.get已经被调用")
        return name
    }
    operator fun setValue(thisRef:Any?, property: KProperty<*>, value:String)
    {
        println("setValue被调用");
        println("${className}.set已经被调用")
        name = value

    }
}
fun main(args: Array<String>)
{
    var c1 = MyClass11()
    var c2 = MyClass22()

    c1.name = "Bill"
    c2.name = "Mike"

    println(c1.name)
    println(c2.name)
}

输出:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/yulu5216/article/details/80205621