Kotlin 委派 (Delegation)

委派 (Delegation) 是一種設計模式,將某個物件的工作「外包」給另一個物件處理。 Kotlin 原生支援了 Class DelegationProperty Delegation,讓這種模式變得超級簡單,核心關鍵字就是 by

Class Delegation (類別委派)

這是一種取代「繼承」的好方法 (Composition over Inheritance)。 假設你想實作一個 List,但只想修改其中幾個方法的行為,其他都照舊。

interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() = println(x)
}

// Derived 類別實作 Base 介面,但它把所有工作都「委派」給 b 這個物件
class Derived(b: Base) : Base by b

fun main() {
    val b = BaseImpl(10)
    Derived(b).print() // 輸出 10
}

你不需要手動寫 override fun print() { b.print() },編譯器幫你做掉了。

Property Delegation (屬性委派)

這是 Kotlin 最神奇的功能之一。 你可以把屬性的 get()set() 邏輯外包給一個代理物件。

語法:val/var <property name>: <Type> by <expression>

1. 延遲初始化 (lazy)

最常用的標準委派。變數只會在 第一次被存取時 才執行初始化程式碼。

val heavyData: String by lazy {
    println("Computing...")
    // 模擬耗時操作
    Thread.sleep(1000)
    "Result"
}

fun main() {
    println("Start")
    println(heavyData) // 印出 "Computing..." 然後 "Result"
    println(heavyData) // 直接印出 "Result" (不會再計算)
}

2. 觀察者 (observable)

當屬性值改變時,自動執行 callback。

var name: String by Delegates.observable("Initial") { prop, old, new ->
    println("$old -> $new")
}

fun main() {
    name = "Miko" // 輸出 Initial -> Miko
    name = "Jason" // 輸出 Miko -> Jason
}

3. Map 委派

可以直接用 Map 來儲存屬性值 (常用於解析 JSON 或動態設定)。

class User(val map: Map<String, Any?>) {
    val name: String by map
    val age: Int     by map
}

val user = User(mapOf(
    "name" to "John Doe",
    "age"  to 25
))
println(user.name) // John Doe

總結

  • by 關鍵字:一切委派的核心。
  • by lazy:最常用,省資源神器。
  • Delegation Pattern:用組合取代繼承,降低耦合。