1.自定義代理
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef,thanks you for delegating"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to in $thisRef")
}
}
上面的示例就是針對String這個類型的屬性的代理類實現(xiàn)贬墩,用法如下
class Example {
var p: String by Delegate()
}
在此類被使用的時候定踱,對p
變量的幅值和取值都會經(jīng)過代理類
val e = Example()
e.p = "a"
print(e.p)
此時會依次打印出
a has been assigned to in Example@79fc0f2f
Example@79fc0f2f,thanks you for delegating
2.標準代理庫
import kotlin.properties.Delegates
Kotlin標準庫中實現(xiàn)了一個代理工廠類Delegates,可以很方便的被使用痪欲,以下是官網(wǎng)上介紹的幾種
lazy (延遲賦值庸疾?)
val v: String by lazy {
println("delegate")
"hello"
}
fun main(args: Array<String>) {
print(v)
print(v)
}
可以看到的是lazy實現(xiàn)的是一種lambda調用方法吸申。
lazy在變量第一次被賦值之前插入一段操作锦聊,因此最后的結果是輸出了一次delegate歹嘹,兩次hello
observable (觀察者?)
class User {
var name: String by Delegates.observable("default") {
property, oldValue, newValue ->
println("$property $oldValue -> $newValue")
}
}
fun main(args: Array<String>) {
val user = User()
user.name = "first"
user.name = "second"
}
Delegates.observable定義兩個參數(shù)孔庭,一個是初始值尺上,一個就是監(jiān)聽值的修改的方法,使用lambda表達式的參數(shù)就是property, oldValue, newValue這三個圆到,顧名思義即可怎抛。
因此輸出的結果是:
var User.name: kotlin.String default -> first
var User.name: kotlin.String first -> second
3.存儲屬性map
class User(map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
fun main(args: Array<String>) {
val user = User(mapOf(
"name" to "john",
"age" to 11
))
println(user.name)
println(user.age)
}
使用map存儲屬性鍵值對進行代理初始化
4.代理類屬性 總結
要實現(xiàn)一個代理類所要所的事如下:
- 對于只讀屬性,需要實現(xiàn)
getValue
方法芽淡,參數(shù)包括 :thisRef
- 必須是所代理類型或其超類马绝,property
-必須是KProperty<*>
或其超類 - 對于可變類型,需要實現(xiàn)
getValue
和setValue
方法挣菲,setValue
方法除了最后一個附加參數(shù)必須是其代理類型之外富稻,其他類型與getValue
相同
如果不清楚具體寫法,可以直接通過實現(xiàn)標準庫中的接口來定義自己的代理類:下面就是標準庫中給出的接口
interface ReadOnlyProperty<in R, out T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
}
interface ReadWriteProperty<in R, T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
operator fun setValue(thisRef: R, property: KProperty<*>, value: T)
}
翻譯規(guī)則(看看就行了)
class C {
var prop: Type by MyDelegate()
}
// this code is generated by the compiler instead:
class C {
private val prop$delegate = MyDelegate()
var prop: Type
get() = prop$delegate.getValue(this, this::prop)
set(value: Type) = prop$delegate.setValue(this, this::prop, value)
}
*Providing a delegate
一個類似getValue
的代理接口provideDelegate
class ResourceLoader<T>(id: ResourceID<T>) {
operator fun provideDelegate(
thisRef: MyUI,
prop: KProperty<*>
): ReadOnlyProperty<MyUI, T> {
checkProperty(thisRef, prop.name)
// create delegate
}
private fun checkProperty(thisRef: MyUI, name: String) { ... }
}
fun <T> bindResource(id: ResourceID<T>): ResourceLoader<T> { ... }
class MyUI {
val image by bindResource(ResourceID.image_id)
val text by bindResource(ResourceID.text_id)
}
原因是如果要實現(xiàn)相同的效果白胀,不用此方法而是使用getValue
方法的話不太優(yōu)雅椭赋,例如:
// Checking the property name without "provideDelegate" functionality
class MyUI {
val image by bindResource(ResourceID.image_id, "image")
val text by bindResource(ResourceID.text_id, "text")
}
fun <T> MyUI.bindResource(
id: ResourceID<T>,
propertyName: String
): ReadOnlyProperty<MyUI, T> {
checkProperty(this, propertyName)
// create delegate
}