1. 類的委託
委託模式 給實現繼承提供了很好的代替方式, Kotlin 在語法上支持這一點,所以並
不需要什麼樣板代碼。 Derived 類可以繼承 Base 接口並且指定一個對象代理
它全部的公共方法:
// 類的委託
// AOP(面向方面編程)
interface Base
{
fun print()
}
class BaseImpl(val x:Int):Base
{
override fun print() {
println(x)
}
}
class Child1(b:Base):Base by b
{
fun getName():String
{
return "Bill"
}
}
class Child2(b:Base):Base by b
{
}
class Child3(b:Base):Base by b
{
}
fun main(args: Array<String>)
{
val b = BaseImpl(10)
Child1(b).print()
Child2(b).print()
Child3(b).print()
}
在 Child1的父類列表中的 by 從句會將 b 存儲在 Child1內部對象,並
且編譯器會生成 Base 的所有方法並轉給 b 。
2. 委託屬性
很多常用屬性,雖然我們可以在需要的時候手動實現它們,但更好的辦法是一次實
現多次使用,並放到庫。比如:
- 延遲屬性:只在第一次訪問是計算它的值
- 觀察屬性:監聽者從這獲取這個屬性
更新的通知 在 map 中存儲的屬性,而不是單獨存在分開的字段爲了滿足這些情形,Kotllin 支持代理屬性:
class Example {
var p: String by Delegate()
}
語法結構是: val/var : by 在 by 後
面的屬性就是代理,這樣這個屬性的 get() 和 set() 方法就代理給了它。
屬性代理不需要任何接口的實現,但必須要提供 get() 方法(如果是變量還需要
set() 方法)。像這樣:
class MyClass1
{
// 將name屬性委託給Delegate類
var name:String by Delegate()
}
class MyClass2
{
var name:String by Delegate()
}
// 屬性委託類
class Delegate
{
var name:String = ""
operator fun getValue(thisRef:Any?, property:KProperty<*>):String
{
// 獲取thisRef指定的類名
val className = thisRef.toString().substringBefore('@')
println("getValue被調用")
println("${className}.get已經被調用")
return name
}
operator fun setValue(thisRef:Any?, property:KProperty<*>,value:String)
{
// 獲取thisRef指定的類名
val className = thisRef.toString().substringBefore('@')
println("setValue被調用")
println("${className}.set已經被調用")
name = value
}
}
fun main(args: Array<String>)
{
var c1 = MyClass1()
var c2 = MyClass2()
c1.name = "Bill"
c2.name = "Mike"
println(c1.name)
println(c2.name)
}
輸出:
委託屬性的要求:
只讀屬性 (val),委託必須提供一個名字叫 get 的方法並接受如下參數:
- 接收者–必須是相同的,或者是屬性擁有者的子類型
- 元數據–必須是 PropertyMetadata 或這它的子類型
這個函數必須返回同樣的類型作爲屬性。
可變屬性 (var),委託必須添加一個叫 set 的函數並接受如下參數:
- 接受者–與 get() 一樣 元數據–與 get() 一樣
- 新值–必須和屬性類型一致 或是它的字類型
3.委託類的初始化函數
如果委託類有主構造器,也可以向主構造器傳入一個初始化函數。這是可以定義一個委託函數的返回值是委託類,並在委託時指定初始化函數。
import kotlin.reflect.KProperty
// 委託類的初始化函數
public fun <T> delegate(initializer:()->T):Delegate1<T> = Delegate1(initializer)
class MyClass11
{
// 將name屬性委託給delegate
var name:String by delegate {
println("MyClass1.name初始化函數調用")
"<MyClass1>"
}
}
class MyClass22
{
var name:String by delegate {
println("MyClass2.name初始化函數調用")
"<MyClass2>"
}
}
// 屬性委託類
class Delegate1<T>(initializer:()->T)
{
var name:String = ""
var className = initializer()
operator fun getValue(thisRef:Any?, property: KProperty<*>):String
{
println("getValue被調用")
println("${className}.get已經被調用")
return name
}
operator fun setValue(thisRef:Any?, property: KProperty<*>, value:String)
{
println("setValue被調用");
println("${className}.set已經被調用")
name = value
}
}
fun main(args: Array<String>)
{
var c1 = MyClass11()
var c2 = MyClass22()
c1.name = "Bill"
c2.name = "Mike"
println(c1.name)
println(c2.name)
}
輸出: