文章

Kotlin高级——委托

开始

委托模式是将一个对象的职责委托给其他对象完成,kotlin委托通过by关键字实现

类委托

将类中的方法委托到被委托对象实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface Method {
    fun method()
}

class MethodImpl : Method {
    override fun method() {
        // statement
    }
}
// 委托类与被委托类实现同一接口
class Person(method: Method) : Method by method {
    // 委托类中自动生成了接口中的方法,并将调用转发给被委托对象
    
    // 当委托类重写了接口方法时,调用委托类重写的方法
    override fun method() {
        // statement
    }
}

属性委托

在属性后使用by关键字加一个表达式,表达式返回被委托对象,将属性的定义委托给该对象管理

属性的getter和setter被委托给这个对象的getValue和setValue方法(val属性只需提供getValue方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
class Person {
    var name: String by Delegate()
}

class Delegate : ReadWriteProperty<Person, String> {
    override operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "$thisRef, 这里委托了 ${property.name} 属性"
    }

    override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("$thisRef 的 ${property.name} 属性赋值为 $value")
    }
}

by-lazy延迟初始化是调用了lazy函数,lazy函数传入一个闭包,返回一个Lazy对象,属性定义由Lazy对象管理

Lazy对象只实现了getValue方法,因此通常用于val属性的延迟初始化

将属性委托到映射

1
2
3
4
5
6
7
8
9
10
// Map为只读map
class Person(val map: Map<String, Any?>) {
    val name: String by map
    val age: Int by map
}
// MutableMap为可变map
class Student(val map: MutableMap<String, Any?>) {
    var name: String by map
    var age: Int by map
}

可观察属性

kotlin的Delegates类的observable方法可以实现属性的观察者,observable方法传入一个初始值和一个观察者处理器闭包

1
2
3
4
5
6
7
8
import kotlin.properties.Delegates

class Person {
    var name: String by Delegates.observable("initValue") {
        property, oldValue, newValue -> 
        // statement
    }
}

Delegates.notNull

用于对一个非空var属性进行延迟初始化

lateinit不支持原始类型,Delegates.notNull支持所有非空类型

当属性委托给notNull后,若未进行初始化直接访问会抛出异常

1
2
3
4
5
import kotlin.properties.Delegates

class Person {
   	var age: Int by Delegates.notNull<Int>()
}

自定义委托

创建一个类作为被委托类,对于val属性,需要实现getValue操作符,对于var属性,需要实现setValue和getValue操作符

  • 当属性为var时,被委托对象继承ReadWriteProperty,重写setValue和getValue
  • 当属性为val时,被委托对象继承ReadOnlyProperty,重写getValue
1
2
3
4
5
6
7
8
9
10
11
12
class Delegate : ReadWriteProperty<Person, String> {
    // thisRef:委托对象的引用,类型可以是委托对象类型或其父类型
    // property:KProperty类型,存储属性的元数据
    // 返回值:返回属性对应类型或其子类型
    override operator fun getValue(thisRef: Person, property: KProperty<*>): String {
        return "$thisRef, 这里委托了 ${property.name} 属性"
    }
	// value:新值,必须是属性对应类型或其父类型
    override operator fun setValue(thisRef: Person, property: KProperty<*>, value: String) {
        println("$thisRef 的 ${property.name} 属性赋值为 $value")
    }
}

provideDelegate

用于定义创建被委托对象时的逻辑

通过provider委托时,优先调用provideDelegate,再调用getValue/setValue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Person {
    var name: String by DelegateProvider()
}

class Delegate : ReadWriteProperty<Person, String> {
    override operator fun getValue(thisRef: Person, property: KProperty<*>): String {
        return ""
    }

    override operator fun setValue(thisRef: Person, property: KProperty<*>, value: String) {
        // statement
    }
}
// 委托提供者
class DelegateProvider {
    operator fun provideDelegate(person: Person, property: KProperty<*>) : ReadWriteProperty<Person, String> {
        // statement
        return Delegate() // 返回一个委托对象
    }
}
本文由作者按照 CC BY 4.0 进行授权