天天看點

kotlin_委托

kotlin

文章目錄

  • ​​kotlin​​
  • ​​1 類委托​​
  • ​​2 委托加強​​
  • ​​3 屬性委​​
  • ​​4 标準委托​​
  • ​​4.1 惰性加載:bylazy​​
  • ​​4.2 延遲加載:lateinit​​
  • ​​5 可觀察屬性 Observable​​
  • ​​6 把屬性儲存在映射中​​

委托模式是軟體設計模式中的一項基本技巧。在委托模式中,有兩個對象參與處理同一個請求,接受請求的對象将請求委托給另一個對象來處理。

Kotlin 直接支援委托模式,更加優雅,簡潔。Kotlin 通過關鍵字 by 實作委托。

1 類委托

類的委托即一個類中定義的方法實際是調用另一個類的對象的方法來實作的。

以下執行個體中派生類 Derived 繼承了接口 Base 所有方法,并且委托一個傳入的 Base 類的對象來執行這些方法。

fun main(args: Array) {
    val small = SmallHeadFather()
    small.wash()
}

interface Water{
    fun wash()
}

class BigHeadSon:Water{
    override fun wash() {
        println("大頭兒子")
    }
}
class SmallHeadFather:Water by BigHeadSon()
      

結果

大頭兒子

通過by将小頭爸爸的工作給了大頭兒子,然後委托大頭兒子進行洗的操作。

第二種方法的類委托:更友善和可擴充

fun main(args: Array) {
    val big = BigHeadSon1()
    val s1 = SmallHeadSon1(big)
    s1.wash()

}

class BigHeadSon1:Water{
    override fun wash() {
        println("大頭兒子")
    }
}

class SmallHeadSon1(var Water:Water):Water by Water
      

class SmallHeadSon1(var Water:Water):Water by Water

注意文法格式

2 委托加強

如果想委托别的事情的話稱為委托加強

fun main(args: Array) {
    val big = BigHeadSon2()
    var s1 = SmallHeadSon2(big)
    s1.wash()
}
class BigHeadSon2:Water{
    override fun wash() {
        println("大頭兒子")
    }
}

class SmallHeadSon2(var Water:Water):Water by Water{
    override fun wash() {
        println("付錢")
        Water.wash()
        println("幹的好,下次加油")
    }
}
      

加強了付錢和幹得好,下次加油兩句話

3 屬性委

屬性委托指的是一個類的某個屬性值不是在類中直接進行定義,而是将其托付給一個代理類,進而實作對該類的屬性統一管理。

屬性委托文法格式:

val/var <屬性名>: <類型> by <表達式>
      
  • var/val:屬性類型(可變/隻讀)
  • 屬性名:屬性名稱
  • 類型:屬性的資料類型
  • 表達式:委托代理類

by 關鍵字之後的表達式就是委托, 屬性的 get() 方法(以及set() 方法)将被委托給這個對象getValue() 和 setValue() 方法。屬性委托不必實作任何接口, 但必須提供 getValue() 函數(對于 var屬性,還需要 setValue() 函數)。

fun main(args: Array) {
    var b1 = BigHeadSon3()
    b1.money = 100
    println(b1.money)
}

class BigHeadSon3{
    var money:Int by Mother()
}
class Mother{
    var money = 0
    var sonmoney = 0
    operator fun getValue(bigHeadSon3: BigHeadSon3, property: KProperty<*>): Int {
        return sonmoney
    }

    operator fun setValue(bigHeadSon3: BigHeadSon3, property: KProperty<*>, i: Int) {
        money = i - 50
        sonmoney = 50

    }
}
      

相當于本來兒子有100元錢,媽媽從中拿了50元錢,列印出來的是兒子還有的錢

4 标準委托

Kotlin 的标準庫中已經内置了很多工廠方法來實作屬性的委托。

4.1 惰性加載:bylazy

lazy() 是一個函數, 接受一個 Lambda 表達式作為參數, 傳回一個 Lazy 執行個體的函數,傳回的執行個體可以作為實作延遲屬性的委托: 第一次調用 get() 會執行已傳遞給 lazy() 的 lamda 表達式并記錄結果, 後續調用 get() 隻是傳回記錄的結果。

val lazyValue: String by lazy {
    println("computed!")     // 第一次調用輸出,第二次調用不執行
    "Hello"
}

fun main(args: Array) {
    println(lazyValue)   // 第一次執行,執行兩次輸出表達式
    println(lazyValue)   // 第二次執行,隻輸出傳回值
}
      

執行輸出結果:

computed!

Hello

Hello

4.2 延遲加載:lateinit

用的時候指派,不用的時候不可以指派

fun main(args: Array) {
    var p1 = Person()
    p1.name1 = "amituofue"
    p1.setName("amituofo")
}
class Person{
    lateinit var name1:String
    fun setName(name:String){
        this.name1 = name
    }
}
      

總結

1.bylazy和lateinit都可以單獨使用或者放到成員變量中使用

2.bylazy知道具體的值,用的時候再加載

3.lateinit不知道具體的值,後面在指派

4.bylazy需要用val修飾,lateinit需要用var指派

5 可觀察屬性 Observable

observable 可以用于實作觀察者模式。

Delegates.observable() 函數接受兩個參數: 第一個是初始化值, 第二個是屬性值變化事件的響應器(handler)。

在屬性指派後會執行事件的響應器(handler),它有三個參數:被指派的屬性、舊值和新值:

import kotlin.properties.Delegates

class User {
    var name: String by Delegates.observable("初始值") {
        prop, old, new ->
        println("舊值:$old -> 新值:$new")
    }
}

fun main(args: Array) {
    val user = User()
    user.name = "第一次指派"
    user.name = "第二次指派"
}
      

執行輸出結果:

舊值:初始值 -> 新值:第一次指派

舊值:第一次指派 -> 新值:第二次指派

6 把屬性儲存在映射中

class Site(val map: Map) {
    val name: String by map
    val url: String  by map
}

fun main(args: Array) {
    // 構造函數接受一個映射參數
    val site = Site(mapOf(
        "name" to "菜鳥教程",
        "url"  to "www.runoob.com"
    ))
    
    // 讀取映射值
    println(site.name)
    println(site.url)
}