委托跟代理模式很类似,就是让别的类来帮助协作,也就是我委托你做一些事情,我把相应的方法告知你之后借助你的对象的能力来帮我做一些事情。

首先

1、类委托

先看如下代码:

interface Outoutable{
    fun output(msg: String)
    var type: String
}

很简单定义一个接口

class DefoultOutput() : Outoutable{
    override fun output(msg: String) {
        for(i in 1..6){
            println("<h${i}>${msg}</h${i}>")
        }
    }

//    override var type: String = "输出设备"
    override var type: String
        get() = "输出设备"
        set(value) {}

}
class Printer(b: DefoultOutput): Outoutable by b

接着再写一个子类实现这个接口,实现两个方法

然后在main()方法里面调用:

val output = DefoultOutput()
val printer = Printer(output)
printer.output("fkit.org")
println(printer.type)

输出如下:

<h1>fkit.org</h1>
<h2>fkit.org</h2>
<h3>fkit.org</h3>
<h4>fkit.org</h4>
<h5>fkit.org</h5>
<h6>fkit.org</h6>
输出设备

最重要的就是by这个关键字了,这里我们将形参里面的b作为委托对象,因为我们委托类也实现了接口,所以委托类的对象就可以代替委托对象,调用里面的方法了。

接下来再看看这种形式:

class Project(): Outoutable by DefoultOutput(){
    override fun output(msg: String) {
        println("project $msg")
    }
}

我们发现没有形参了,而是通过by直接创建委托对象,并且主动实现了output方法,那么问题来了,打印会是怎么样子呢?

project fkit.lcs

当然会打印如上内容,重写方法之后发现委托类里面包含重写的方法,会优先调用委托类的方法。

2、委托属性

委托属性是说让其他类来操纵此属性,受委托类提供get/set方法以供外界调用,当我们需要把多个类的属性集中起来调用使用的时候我们可以使用委托属性,可以很方便的实现。

先看第一种方案

class Example {
    var eg: String by Delegate()
}
class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, thank you for delegating '${property.name}' to me!"
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$value has been assigned to '${property.name}' in $thisRef.")
    }
}

其实也是通过by关键字实现的,交由给Delegate类来提供set和get方法,也就是setVlaue和getValue方法,参数thisRef代表是对象本身,property参数是指委托的属性,我们可以.name拿到里面的具体的数值。

第二种方案

当我们属性值被改动之后我们想要立马接收到通知,这个就有点像观察者模式了,具体使用如下:

class Person(name:String,age:Int){
    var age:Int by Delegates.observable(age){ property, oldValue, newValue ->
        println("${property.name} oldValue = $oldValue newValue = $newValue")
    }
    var name:String by Delegates.observable(name){ property, oldValue, newValue ->
        println("${property.name} oldValue = $oldValue newValue = $newValue")
    }
}

我们省略了代理类,直接by Delegates.observable即可,里面我们可以看到有旧的数值以及被新赋值的参数,可以做好数值改变之后的逻辑。

Kotlin会为委托属性生成辅助属性,该辅助属性引用了属性的委托对象。当程序调用委托属性的时候,实际上执行的是委托对象的getVlaye()、setValue()方法。

我们可以看到不管我们如何设置,最后的结果都是会设置成功的。

还有一种我们需要人为的设置一个条件,是否能够设置成功?看下面代码:

var test: Int by Delegates.vetoable(20) { property, oldValue, newValue ->
    println("${property}${oldValue}被修改为${newValue}")
    newValue > oldValue
}

我们发现我们用的是Delegates.vetoable,并且返回一个boolean值开控制是否设置成功,我们在main()方法里面如下调用:

println(test)
test = 15
println(test)
test = 25
println(test)

输入如下:

20
property test (Kotlin reflection is not available)的20被修改为15
20
property test (Kotlin reflection is not available)的20被修改为25
25

实际上当我们的条件不允许的时候我们的修改是不会成功的。

第三个

延迟属性即lazy操作符

我们看看它是怎么使用的

//延迟加载
val lazyProp: String by lazy {
    println("第一次进来")
    "函数返回值"
}
//验证lazy功能,连续调用两次方法
println(lazyProp)
println(lazyProp)

我们发现连续调用两次方法看输出情况:

第一次进来
函数返回值
函数返回值

可以看到当第二次进来的时候就直接返回第一次得到的数值。

委托大概的内容基本上先这些吧!

05-16 08:11