委託跟代理模式很類似,就是讓別的類來幫助協作,也就是我委託你做一些事情,我把相應的方法告知你之後藉助你的對象的能力來幫我做一些事情。
首先
1、類委託
先看如下代碼:
interface Outoutable{ fun output(msg: String) var type: String }
很簡單定義一個接口
class DefoultOutput() : Outoutable{ override fun output(msg: String) { for(i in 1..6){ println("<h${i}>${msg}</h${i}>") } } // override var type: String = "輸出設備" override var type: String get() = "輸出設備" set(value) {} }
class Printer(b: DefoultOutput): Outoutable by b
接着再寫一個子類實現這個接口,實現兩個方法
然後在main()方法裏面調用:
val output = DefoultOutput() val printer = Printer(output) printer.output("fkit.org") println(printer.type)
輸出如下:
<h1>fkit.org</h1>
<h2>fkit.org</h2>
<h3>fkit.org</h3>
<h4>fkit.org</h4>
<h5>fkit.org</h5>
<h6>fkit.org</h6>
輸出設備
最重要的就是by這個關鍵字了,這裏我們將形參裏面的b作爲委託對象,因爲我們委託類也實現了接口,所以委託類的對象就可以代替委託對象,調用裏面的方法了。
接下來再看看這種形式:
class Project(): Outoutable by DefoultOutput(){ override fun output(msg: String) { println("project $msg") } }
我們發現沒有形參了,而是通過by直接創建委託對象,並且主動實現了output方法,那麼問題來了,打印會是怎麼樣子呢?
project fkit.lcs
當然會打印如上內容,重寫方法之後發現委託類裏面包含重寫的方法,會優先調用委託類的方法。
2、委託屬性
委託屬性是說讓其他類來操縱此屬性,受委託類提供get/set方法以供外界調用,當我們需要把多個類的屬性集中起來調用使用的時候我們可以使用委託屬性,可以很方便的實現。
先看第一種方案
class Example { var eg: String by Delegate() }
class Delegate { operator fun getValue(thisRef: Any?, property: KProperty<*>): String { return "$thisRef, 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.") } }
其實也是通過by關鍵字實現的,交由給Delegate類來提供set和get方法,也就是setVlaue和getValue方法,參數thisRef代表是對象本身,property參數是指委託的屬性,我們可以.name拿到裏面的具體的數值。
第二種方案
當我們屬性值被改動之後我們想要立馬接收到通知,這個就有點像觀察者模式了,具體使用如下:
class Person(name:String,age:Int){ var age:Int by Delegates.observable(age){ property, oldValue, newValue -> println("${property.name} oldValue = $oldValue newValue = $newValue") } var name:String by Delegates.observable(name){ property, oldValue, newValue -> println("${property.name} oldValue = $oldValue newValue = $newValue") } }
我們省略了代理類,直接by Delegates.observable即可,裏面我們可以看到有舊的數值以及被新賦值的參數,可以做好數值改變之後的邏輯。
Kotlin會爲委託屬性生成輔助屬性,該輔助屬性引用了屬性的委託對象。當程序調用委託屬性的時候,實際上執行的是委託對象的getVlaye()、setValue()方法。
我們可以看到不管我們如何設置,最後的結果都是會設置成功的。
還有一種我們需要人爲的設置一個條件,是否能夠設置成功?看下面代碼:
var test: Int by Delegates.vetoable(20) { property, oldValue, newValue -> println("${property}的${oldValue}被修改爲${newValue}") newValue > oldValue }
我們發現我們用的是Delegates.vetoable,並且返回一個boolean值開控制是否設置成功,我們在main()方法裏面如下調用:
println(test) test = 15 println(test) test = 25 println(test)
輸入如下:
20
property test (Kotlin reflection is not available)的20被修改爲15
20
property test (Kotlin reflection is not available)的20被修改爲25
25
實際上當我們的條件不允許的時候我們的修改是不會成功的。
第三個
延遲屬性即lazy操作符
我們看看它是怎麼使用的
//延遲加載 val lazyProp: String by lazy { println("第一次進來") "函數返回值" }
//驗證lazy功能,連續調用兩次方法
println(lazyProp)
println(lazyProp)
我們發現連續調用兩次方法看輸出情況:
第一次進來
函數返回值
函數返回值
可以看到當第二次進來的時候就直接返回第一次得到的數值。
委託大概的內容基本上先這些吧!