委託模式已已經證明是實現繼承的一個很好的替代方式
Kotlin 中 by 就是用於實現委託的。
fun main(args: Array<String>) {
val b =BaseImpl("base")
Derived(b).print()
}
interface Base{
fun print()
}
class BaseImpl(val x :String):Base{
override fun print() = print(x)
}
class Derived(b: Base) :Base by b
Derived 的父類列表中的by子句 會將b 存儲Derived內部,並且編譯器會生成所有b類型的方法
覆蓋由委託實現的接口成員
fun main(args: Array<String>) {
val b =BaseImpl("base")
val derived = Derived(b)
derived.printLine()//base----base
derived.printMessage()//Derived
println(derived.message)//Derived----
}
interface Base{
val message :String
fun printMessage()
fun printLine()
}
class BaseImpl(val x :String):Base{
override val message: String="base----$x"
override fun printMessage() = print(x)
override fun printLine() = println(message)
}
class Derived(b: Base) :Base by b{
override val message: String="Derived----"
override fun printMessage() = print("Derived")
}
Derived 可以重寫方法,但是重寫的成員不會在委託對象的成員中調用
屬性委託
屬性委託的語法: val/var <屬性名>: <類型> by <表達式>
屬性委託不需要實現任何接口但是要重寫setValue 和 getValue 方法
class Delegate{
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "${thisRef?.javaClass}, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in ${thisRef?.javaClass}.")
}
}
fun main(args: Array<String>) {
val example=Example()
print(example.str)//class sample.xietaichen.koinsample.Example, thank you for delegating 'str' to me!
example.str="aaa"//aaa has been assigned to 'str' in sample.xietaichen.koinsample.Example@19469ea2.
}
class Example{
var str :String by Delegate()
}
當我們從委託到一個 Delegate實例的 str讀取時,將調用Delegate中的 getValue() 函數, 所以它第一個參數是讀出str的對象、第二個參數保存了對str自身的描述 (例如你可以取它的名字)。
setValue 同理
對於一個只讀屬性(即 val 聲明的),委託必須提供一個名爲 getValue 的函數,該函數接受以下參數:
thisRef —— 必須與 屬性所有者 類型(對於擴展屬性——指被擴展的類型)相同或者是它的超類型;
property —— 必須是類型 KProperty<*> 或其超類型。
這個函數必須返回與屬性相同的類型(或其子類型)
對於一個可變屬性(即 var 聲明的),委託必須額外提供一個名爲 setValue 的函數,該函數接受以下參數:
thisRef —— 同 getValue();
property —— 同 getValue();
new value —— 必須與屬性同類型或者是它的超類型。
getValue() 或/與 setValue() 函數可以通過委託類的成員函數提供或者由擴展函數提供。 當你需要委託屬性到原本未提供的這些函數的對象時後者會更便利。 兩函數都需要用 operator 關鍵字來進行標記。
委託類可以實現包含所需 operator 方法的 ReadOnlyProperty 或 ReadWriteProperty 接口之一
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)
}