Kotlin 委派 (Delegation)
委派 (Delegation) 是一種設計模式,將某個物件的工作「外包」給另一個物件處理。
Kotlin 原生支援了 Class Delegation 和 Property 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:用組合取代繼承,降低耦合。