目錄
- 類委託
- 屬性委託
2.1. 方法一:可以按需繼承
ReadOnlyProperty、ReadWriteProperty
兩個介面中的一個; 2.2. 方法二:自己定義,但方法引數必須和 1 中介面的方法引數一致; - 標準委託 3.1. 延遲屬性 Lazy 3.2. 可觀察屬性 Observable 3.3. 把屬性儲存在對映中
- 使用場景
類委託(代理模式)
類的兩種代理方法
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
// 第一種:這裡直接使用關鍵字 by 進行代理
class Derived(base: Base) : Base by base
// 第二種:
class Derived(base: Base) : Base {
val base : Base
init {
this.base = base
}
override fun print() {
base.print() // base是BaseImpl的例項物件
}
}
// 測試
class Main {
fun main() {
val b = BaseImpl(10)
Derived(b).print() // prints 10
}
}
複製程式碼
屬性委託
語法結構: val/var <property name>: <Type> by <expression>
兩種實現方法:
-
方法一:可以按需繼承
ReadOnlyProperty、ReadWriteProperty
兩個介面中的一個;// 讀取屬性 public interface ReadOnlyProperty<in R, out T> { public operator fun getValue(thisRef: R, property: KProperty<*>): T } // 讀寫屬性 public interface ReadWriteProperty<in R, T> { // 關鍵字 operator 過載操作符 public operator fun getValue(thisRef: R, property: KProperty<*>): T public operator fun setValue(thisRef: R, property: KProperty<*>, value: T) } 複製程式碼
示例程式碼:
class Delegate<T> : ReadWriteProperty<Any?, T> { // 重寫了getValue()方法 override fun getValue(thisRef: Any?, property: KProperty<*>): T { return ... } override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { } } class Main { var p: String by Delegate<String>() fun test() { val main = Main() print(main.p) // 會呼叫到Delegate中的getValue()方法 main.p = "Elson" // 會呼叫到Delegate中的setValue()方法 } } 複製程式碼
-
方法二:自己定義,但方法引數必須和 1 中介面的方法引數一致;
class Delegate<T> { // 使用關鍵字 operator 來實現過載 operator fun getValue(thisRef: Any?, property: KProperty<*>): T { return "$thisRef, thank you for delegating '${property.name}' to me!" } operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { println("$value has been assigned to '${property.name}' in $thisRef.") } } 複製程式碼
示例程式碼:
class Main { var p: String by Delegate<String>() //屬性 p 被代理 fun test() { val main = Main() print(main.p) // 會呼叫到Delegate中的getValue()方法 main.p = "Elson" // 會呼叫到Delegate中的setValue()方法 } } 複製程式碼
標準委託
1. 延遲屬性 Lazy
-
示例程式碼:
val lazyValue: String by lazy { println("computed!") "Hello" } fun main(args: Array<String>) { println(lazyValue) //第一次呼叫lazyValue時,會先初始化lazy{}作用區間的程式碼,即列印一個"computed!",然後返回一個"Hello"字串並賦值給lazyValue; println(lazyValue) //第二次呼叫lazyValue時,直接將"Hello"賦值給lazyValue;可參考下面的原始碼 } 複製程式碼
-
原始碼:
Lazy.kt
檔案public fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer) private object UNINITIALIZED_VALUE @JvmVersion private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable { private var initializer: (() -> T)? = initializer @Volatile private var _value: Any? = UNINITIALIZED_VALUE // final field is required to enable safe publication of constructed instance private val lock = lock ?: this override val value: T get() { val _v1 = _value if (_v1 !== UNINITIALIZED_VALUE) { @Suppress("UNCHECKED_CAST") return _v1 as T //第二次執行操作時,這裡直接返回物件 } return synchronized(lock) { val _v2 = _value if (_v2 !== UNINITIALIZED_VALUE) { @Suppress("UNCHECKED_CAST") (_v2 as T) } else { val typedValue = initializer!!()//第一次使用時執行這裡,將lazy大括號內的程式碼進行初始化,並返回最後一行的資料並賦值給typedValue _value = typedValue initializer = null typedValue } } } override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet." private fun writeReplace(): Any = InitializedLazyImpl(value) } 複製程式碼
2. 可觀察屬性 Observable
示例程式碼:
class User {
// 方法一:
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
// 方法二:Delegates.observable()實際上就是對ObservableProperty的一層封裝
var name : String by object : ObservableProperty<String>("<no name>") {
override fun afterChange(property: KProperty<*>, oldValue: String, newValue: String) {
println("$oldValue -> $newValue")
}
}
}
fun main() {
val user = User()
user.name = "first"
user.name = "second"
}
複製程式碼
輸出結果 < no name > -> first first -> second
原始碼:
public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
}
public inline fun <T> vetoable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean):
ReadWriteProperty<Any?, T> = object : ObservableProperty<T>(initialValue) {
// 需要返回一個boolean值,判斷是否需要發射,預設為true
override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = onChange(property, oldValue, newValue)
}
public abstract class ObservableProperty<T>(initialValue: T) : ReadWriteProperty<Any?, T> {
private var value = initialValue
protected open fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = true
protected open fun afterChange (property: KProperty<*>, oldValue: T, newValue: T): Unit {}
// 代理後,自動被呼叫
public override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
}
// 代理後,自動被呼叫
public override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
val oldValue = this.value
// 判斷是否需要發射,預設為true
if (!beforeChange(property, oldValue, value)) {
return
}
this.value = value
afterChange(property, oldValue, value)
}
}
複製程式碼
3. 把屬性儲存在對映中
這部分不知道怎麼看原始碼
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
複製程式碼