類委託與屬性委託

類委託

類委託就是 現在有一個類需要實現某接口,發現有一個對於這個接口已經實現好的類,可以直接將這個現成的類拿來使用,也就是說本類繼承某接口的任務委託了一個現成已經實現好的類的實例。

interface BASE{
    fun say();
}
interface BASE2{
    fun say2();
}
class SUB: BASE, BASE2{
    override fun say() {
        println("Hello World");
    }
    override fun say2() {
        println("2222");
    }
}
class A: BASE by SUB();
fun main(args: Array<String>) {
    var a = A();
    a.say();
}

屬性委託

類中的屬性也可以委託給現成的類實例,但是如果要是想更改這些屬性的值,實際上是對委託對象內部的操作,需要在被委託的類中實現getValue,setValue。
通過thisRef與p我們定位到我們使用委託對象的那個類中的每個屬性。

class BASE {
    var x: Int by MY();
    /* 
		等價於 var x$MY = MY()
				get() = x$MY.getValue(this, BASE::x)
				set(value) = x$MY.setValue(this, BASE:x, value);
	*/
    var y: Int by MY();
}
class MY {
    var _x:Int = 0;
    var _y:Int = 0;
    operator fun getValue(thisRef:BASE, p:KProperty<*>): Int {
        when(p.name) {
            "x" -> {
                return _x;
            }
            "y" -> {
                return _y;
            }
            else -> {
                return 0;
            }
        }
    }
    operator fun setValue(thisRef: BASE, p:KProperty<*>, value:Int){
        when(p.name) {
            "x" -> {
                _x = value;
            }
            "y" -> {
                _y = value;
            }
        }
    }
}
fun main(args: Array<String>) {
    var b = BASE();
    b.x = 100;
    b.y = 24;
    println("(" + b.x + "," + b.y + ")");
}

延遲屬性

Kotlin提供了一個lazy()函數,該函數接受一個lambda表達式作爲參數,並返回一個Lazy對象作爲委託對象。有個特點就是第一次使用這個屬性的時候會執行整個lambda表達式,第二次以後執行直接返回第一次的返回值。只有val修飾的只讀屬性可以使用lazy標記。

class BASE {
    val str by lazy {
        println("Hello World");
        "HELLO"
    }
}
fun main(args: Array<String>) {
    var base = BASE();
    base.str;
}

屬性監聽

Kotlin在kotlin.properties包中提供了Delegates對象聲明(單例)。
這個對象提供了兩種方法observable()與vetoable()兩個方法用於實現屬性監聽。
函數會返回ReadWriteProperty<Any?, T>類型的委託屬性。兩個屬性的區別在於第一個是無條件的進行賦值,第二個是有條件的賦值,返回爲假就不賦值。

class BASE {
    var x:Int by Delegates.observable(0) {
        prop, old, new ->
            println(""+prop+"屬性的值從"+old+"改爲"+new);
    }

    var y:Int by Delegates.vetoable(0) {
        prop, old, new ->
            println(""+prop+"屬性的值從"+old+"改爲"+new);
            old < new;
    }
}
fun main(args: Array<String>) {
    var base = BASE();
    base.x = 100;
    base.y = -1;
    println(base.y);
}

委託工廠

屬性在初始化時自動回調委託工廠的provideDelegate()方法,然後返回一個ReadWriteProperty<MyTarget,String>對象。
然後通過provideDelegate()返回一個重寫包含getValue()與setValue()的對象就可以。

class BASE {
    var x: Int by MDelegate();
}
class MDelegate{
    operator fun provideDelegate(thisRef:BASE, prop:KProperty<*>):ReadWriteProperty<BASE,Int> {
        return MyDelegate();
    }
    class MyDelegate: ReadWriteProperty<BASE,Int> {
        var _x = 0;
        override fun getValue(thisRef: BASE, property: KProperty<*>): Int {
            return _x;
        }
        override fun setValue(thisRef: BASE, property: KProperty<*>, value: Int) {
            _x = value;
        }
    }
}
fun main(args: Array<String>) {
    var base = BASE();
    base.x = 1;
    println(base.x);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章