8.5 Kotlin课堂:泛型和委托

79 阅读2分钟

泛型

//实现类似apply函数功能
//Any表示泛型具体的类型上限
fun <T : Any> T.build(block: T.() -> Unit): T {
    block()
    return this
}

fun main() {
    val sb = StringBuilder()
    sb.build {
        append("123")
        append("wechat")
    }
    println(sb) //123wechat
}

类委托和委托属性

委托是一种设计模式,它的基本理念是:操作对象自己不会去处理某段逻辑,而是会把工作委托给另外一个辅助对象去处理。

类委托

将一个类的具体实现委托给另一个类去完成。例如,利用helperSet对象去实现MySet类中的功能:

class MySet<T>(val helperSet: HashSet<T>) : Set<T> {
    override val size: Int
        get() = helperSet.size

    override fun contains(element: T) = helperSet.contains(element)
    override fun containsAll(elements: Collection<T>) = helperSet.containsAll(elements)
    override fun isEmpty() = helperSet.isEmpty()
    override fun iterator() = helperSet.iterator()
}

使用场景:让大部分的方法实现调用辅助对象中的方法,少部分的方法实现由自己来重写,甚至加入一些自己独有的方法,那么MySet就会成为一个全新的数据结构类,这就是委托模式的意义所在。 语法糖: Kotlin中委托使用的关键字是by,我们只需要在接口声明的后面使用by关键字,再接上受委托的辅助对象,就可以免去之前所写的一大堆模板式的代码了。如果我们要对某个方法进行重新实现,只需要单独重写那一个方法就可以了,其他的方法仍然可以享受类委托所带来的便利。 MySet就成为了一个全新的数据结构类,它不仅拥有HashSet的全部功能,而且还能打印helloWorld(),这就是Kotlin的类委托所能实现的功能。

class MySet<T>(val helperSet: HashSet<T>) : Set<T> by helperSet {
    fun helloWorld() = println("hello world")
}

属性委托

类委托的核心思想是将一个类的具体实现委托给另一个类去完成,而委托属性的核心思想是将一个属性(字段)的具体实现委托给另一个类去完成。

class MyClass {
    //表示将p属性实现交给Delegate类完成
    //x = p 会自动调用Delegate类中的getValue()方法
    //p = x 会自动调用Delegate类中的setValue()方法
    var p by Delegate()
}

class Delegate {
    var propValue: Any? = null

    //第一个参数表示可以在什么类中使用委托功能
    //KProperty<*>是Kotlin中的一个属性操作类,
    //可用于获取各种属性相关的值,
    //在当前场景下用不着,但是必须在方法参数上进行声明。
    //<*>表示不知道或者不关心泛型的具体类型,只是为了通过编译
    operator fun getValue(myClass: MyClass, kprop: KProperty<*>): Any? {
        return propValue
    }

    operator fun setValue(myClass: MyClass, kprop: KProperty<*>, value: Any?) {
        propValue = value
    }
}

实现lazy懒加载函数

class Later<T>(val block: () -> T) {
    var value: Any? = null

    operator fun getValue(any: Any?, prop: KProperty<*>): T {
        if (value == null) {
            value = block()
        }
        return value as T
    }
}

fun <T> later(block: () -> T) = Later(block)

fun main() {
    //lambda函数只会执行一次
    val p by later { "later string" }
    println(p)
}