Kotlin扩展知识(一):延迟初始化和密封类

Kotlin扩展知识(二):扩展函数和运算符重载

泛型

定义泛型类及函数,语法结构如下:

class MyClass {
    fun <T> method(param: T): T {
        return param
    }
}

调用方式:

val myClass = MyClass()
val result = myClass.method<Int>(123)

之前定义的高级函数 build 如下:

fun StringBuilder.build(block: StringBuilder.() -> Unit): StringBuilder {
    block()
    return this
}

这相当于 apply 函数,但是这个 build 函数只是StringBuilder的扩展函数,只能StringBuilder对象能够使用。定义成泛型,即可其他类型对象也能使用 build 函数,代码如下:

fun <T> T.build(block: T.() -> Unit): T {
    block()
    return this
}

类委托和委托属性

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

Kotlin中也是支持委托功能的,并且将委托功能分为了两种:类委托和委托属性。

类委托

它的核心思想在于将一个类的具体实现委托给另一个类去完成!!

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

    override fun contains(element: T): Boolean = helperSet.contains(element)

    override fun containsAll(elements: Collection<T>): Boolean = helperSet.containsAll(elements)

    override fun isEmpty(): Boolean = helperSet.isEmpty()

    override fun iterator(): Iterator<T> = helperSet.iterator()
}

MySet的构造函数中接收了一个HashSet参数,这就相当于一个辅助对象然后在Set接口所有的方法实现中,我们都没有进行自己的实现,而是调用了辅助对象中相应的方法实现,这其实就是一种委托模式。

写法的好处:

既然都是调用辅助对象的方法实现,那还不如直接使用辅助对象得了。这么说确实没错,但如果我们只是让大部分的方法实现调用辅助对象中的方法,少部分的方法实现由自己来重写,甚至加入一些自己独有的方法,那么MySet就会成为一个全新的数据结构类,这就是委托模式的意义所在。

有个弊端:

如果接口中的待实现方法比较少还好,要是有几十甚至上百个方法的话,每个都去这样调用辅助对象中的相应方法实现,就需要大量的代码书写,在Kotlin中可以通过委托功能来解决!!!

Kotlin中委托的关键字是 by ,我们只需要在接口声明的后面使用by关键字,再接上受委托的辅助对象,就可以免去之前所写的一大堆模板式的代码了!!!代码如下:

class MySet<T>(private val helperSet: HashSet<T>) : Set<T> by helperSet {
    
    fun helloWorld() = println("Hello")
    
    override fun isEmpty(): Boolean = false
    
}

这两段代码实现的效果是一模一样的,但是借助了类委托的功能之后,代码明显简化了太多。另外,如果我们要对某个方法进行重新实现,只需要单独重写那一个方法就可以了,其他的方法仍然可以享受类委托所带来的便利,

委托属性

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

委托属性的语法结构如下:

class MyClass {
    var p by Delegate()
}

这里使用by关键字连接了左边的p属性和右边的Delegate实例,这种写法就代表着将p属性的具体实现委托给了Delegate类去完成。当调用p属性的时候会自动调用Delegate类的getValue()方法,当给p属性赋值的时候会自动调用Delegate类的setValue()方法。

代码如下:

class Delegate{
    var propValue: Any? = null
    operator fun getValue(myClass: MyClass, prop: KProperty<*>): Any? {
        return propValue
    }

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

}

这是一种标准的代码实现模板,在Delegate类中我们必须实现getValue()和setValue()这
两个方法,并且都要使用operator关键字进行声明。

getValue()方法要接收两个参数:

第一个参数用于声明该Delegate类的委托功能可以在什么类中使用,这里写成MyClass表示仅可在MyClass类中使用;

第二个参数KProperty<*>是Kotlin中的一个属性操作类,可用于获取各种属性相关的值,在当前场景下用不着,但是必须在方法参数上进行声明。

另外,<*>这种泛型的写法表示你不知道或者不关心泛型的具体类型,只是为了通过语法编译而已,至于返回值可以声明成任何类型,根据具体的实现逻辑去写就行。

setValue()要接收3个参数。

前两个参数和getValue()方法是相同的;

最后一个参数表示具体要赋值给委托属性的值,这个参数的类型必须和getValue()方法返回值的类型保持一致。

实现一个自己的lazy函数

val p by lazy { ... }

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐