Kotlin学习:委托的理解

Kotlin的委托模式看了官方的还是有一些迷惑,决定写一篇博文记录一下。

委托基础

首先我们要了解委托模式到底是什么:

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

用wiki中的一个简单的例子来说明:

class RealPrinter { // the "delegate"
     void print() { 
       System.out.print("something"); 
     }
 }
 
 class Printer { // the "delegator"
     RealPrinter p = new RealPrinter(); // create the delegate 
     void print() { 
       p.print(); // delegation
     } 
 }
 
 public class Main {
     // to the outside world it looks like Printer actually prints.
     public static void main(String[] args) {
         Printer printer = new Printer();
         printer.print();
     }
 }

在创建的Printer中我们再创建了一个真实的RealPrinter来执行Printer的打印操作。

现在我们看回Kotlin,官方的示例如下:

interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}

class Derived(b: Base) : Base by b

fun main() {
    val b = BaseImpl(10)
    Derived(b).print()
}

这里Derived中的b是一个委托的对象,即上文中的RealPrinter,由这个类来执行真正的打印方法。

在这个例子的基础上我们可以做一下扩展

interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}

class Derived(val b: Base) : Base by b{
    override fun print() { b.print() }
}

fun main() {
    val b = BaseImpl(10)
    Derived(b).print()
}

这其实就是类似java中动态代理的实现,而代理的类就是Derived,它使用了被代理的类中的print方法来执行,我们可以围绕这个print方法增强,类似Spring中的AOP

这里动态代理和委托的区别是,动态代理可以覆写接口中的方法,而委托是不可以覆写接口方法的(相当于用委托类的方法进行覆写),因此不能在原print方法的基础上进行增强,而只能新增一个方法,例如printNew来实现增强

委托属性

先贴官方示例:

import kotlin.reflect.KProperty

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.")
    }
}

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

这里做一下解释。首先,这里的

operator fun getValue/setValue

其实是对应的var p 的get/set方法,也就是用代理对象的get/set替换了p的get/set方法

我们用一个方法测试一下

fun main() {
    val example = Example()
    println(example.p)
    example.p = "1"
}
/* 结果如下
Example@327471b5, thank you for delegating 'p' to me!
1 has been assigned to 'p' in Example@327471b5.

我们发现,调用了代理对象的get/set方法

标准委托

同时,Kotlin官方还提供了几个标准的委托方法

lazy()

lazy其实接收一个supplier类型的lambda函数,所以我们才可以直接才后面开块lazy{ … }

他会在第一次调用属性的get方法时被调用,并且它是基于同步锁的,当然可以通过改变参数mode来实现更改

observable()

接收两个参数,初始值和每次赋值时会调用的handler。

相当于属性在每次执行set的时候,observable都会被调用。这个也是观察者模式的一种典型应用

vetoable()

接收一个初始值和Predicate谓词(即一个返回Boolean的lambda),Predicate有三个参数,property, oldValue, newValue。具体看官方示例

var max: Int by Delegates.vetoable(0) { property, oldValue, newValue ->
    newValue > oldValue
}

println(max) // 0

max = 10
println(max) // 10

max = 5
println(max) // 10

这里property其实就是通过反射获取的属性。而oldValue和newValue该怎么用通过例子就一目了然了。

当Predicate返回true的时候set才会生效

其他的委托大家还是通过Kotlin的官方文档进行学习吧。

总结:委托其实就是通过委托的对象,实现对原代理对象的一些方法或者属性的替换,令其按照委托的对象的方法来执行。

猜你喜欢

转载自blog.csdn.net/qq_41989109/article/details/106175717