Kotlin 委托 #

一、委托概述 #

委托是一种设计模式,将工作委托给其他对象处理。Kotlin 在语言层面支持委托。

二、类委托 #

2.1 基本语法 #

kotlin
interface Base {
    fun print()
}

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

class Derived(b: Base) : Base by b

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

2.2 覆盖委托方法 #

kotlin
interface Base {
    fun print()
}

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

class Derived(b: Base) : Base by b {
    override fun print() { println("Derived") }
}

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

2.3 实际应用 #

kotlin
interface Repository {
    fun findById(id: Int): User?
    fun save(user: User)
}

class BaseRepository : Repository {
    private val users = mutableMapOf<Int, User>()
    
    override fun findById(id: Int) = users[id]
    override fun save(user: User) { users[user.id] = user }
}

class CachedRepository(
    private val delegate: Repository
) : Repository by delegate {
    private val cache = mutableMapOf<Int, User>()
    
    override fun findById(id: Int): User? {
        return cache.getOrPut(id) { delegate.findById(id)!! }
    }
}

三、属性委托 #

3.1 基本语法 #

kotlin
import kotlin.properties.Delegates

class Example {
    var p: String by Delegates.observable("<initial>") { prop, old, new ->
        println("$old -> $new")
    }
}

fun main() {
    val e = Example()
    e.p = "first"   // <initial> -> first
    e.p = "second"  // first -> second
}

3.2 自定义属性委托 #

kotlin
import kotlin.reflect.KProperty

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.")
    }
}

class Example {
    var p: String by Delegate()
}

fun main() {
    val e = Example()
    println(e.p)     // Example@..., thank you for delegating 'p' to me!
    e.p = "NEW"      // NEW has been assigned to 'p' in Example@...
}

3.3 委托接口 #

kotlin
interface ReadOnlyProperty<in T, out V> {
    operator fun getValue(thisRef: T, property: KProperty<*>): V
}

interface ReadWriteProperty<in T, V> {
    operator fun getValue(thisRef: T, property: KProperty<*>): V
    operator fun setValue(thisRef: T, property: KProperty<*>, value: V)
}

四、标准委托 #

4.1 lazy #

kotlin
val lazyValue: String by lazy {
    println("computed!")
    "Hello"
}

fun main() {
    println(lazyValue)  // computed! Hello
    println(lazyValue)  // Hello(不重新计算)
}

4.2 observable #

kotlin
var name: String by Delegates.observable("<initial>") { _, old, new ->
    println("$old -> $new")
}

4.3 vetoable #

kotlin
var max: Int by Delegates.vetoable(0) { _, old, new ->
    new > old  // 只有新值大于旧值才更新
}

4.4 notNull #

kotlin
var name: String by Delegates.notNull()

name = "Kotlin"
println(name)  // Kotlin
// println(name)  // 如果未初始化,抛出异常

五、Map 委托 #

5.1 只读 Map #

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

fun main() {
    val user = User(mapOf(
        "name" to "Kotlin",
        "age" to 10
    ))
    
    println(user.name)  // Kotlin
    println(user.age)   // 10
}

5.2 可变 Map #

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

fun main() {
    val user = User(mutableMapOf(
        "name" to "Kotlin",
        "age" to 10
    ))
    
    user.name = "Java"
    println(user.map)  // {name=Java, age=10}
}

六、提供委托 #

6.1 provideDelegate #

kotlin
class ResourceLoader {
    operator fun provideDelegate(
        thisRef: Any?,
        property: KProperty<*>
    ): ReadOnlyProperty<Any?, String> {
        println("Creating delegate for ${property.name}")
        return object : ReadOnlyProperty<Any?, String> {
            override fun getValue(thisRef: Any?, property: KProperty<*>): String {
                return "Value of ${property.name}"
            }
        }
    }
}

val loader = ResourceLoader()
val prop: String by loader  // Creating delegate for prop

七、实战示例 #

7.1 偏好设置委托 #

kotlin
class PreferenceDelegate<T>(
    private val key: String,
    private val defaultValue: T
) : ReadWriteProperty<Any?, T> {
    
    @Suppress("UNCHECKED_CAST")
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return sharedPreferences.get(key, defaultValue) as T
    }
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        sharedPreferences.put(key, value)
    }
}

class Settings {
    var username: String by PreferenceDelegate("username", "")
    var isLoggedIn: Boolean by PreferenceDelegate("isLoggedIn", false)
}

7.2 数据库属性委托 #

kotlin
class DatabaseProperty<T>(
    private val tableName: String,
    private val id: Long
) : ReadOnlyProperty<Any?, T> {
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T {
        return database.query("SELECT ${property.name} FROM $tableName WHERE id = $id")
    }
}

class User(id: Long) {
    val name: String by DatabaseProperty("users", id)
    val email: String by DatabaseProperty("users", id)
}

7.3 观察者委托 #

kotlin
class ObservableProperty<T>(
    initialValue: T,
    private val onChange: (T) -> Unit
) : ReadWriteProperty<Any?, T> {
    
    private var value = initialValue
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T = value
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        val old = this.value
        this.value = value
        if (old != value) {
            onChange(value)
        }
    }
}

class ViewModel {
    var data: String by ObservableProperty("") {
        println("Data changed to: $it")
        notifyObservers()
    }
}

八、最佳实践 #

8.1 使用标准委托 #

kotlin
// 推荐:使用 lazy
val heavyObject: HeavyObject by lazy { HeavyObject() }

// 推荐:使用 observable
var state: State by Delegates.observable(State.Initial) { _, _, new ->
    notifyStateChanged(new)
}

8.2 封装复杂逻辑 #

kotlin
// 将复杂逻辑封装在委托中
class ValidatedProperty<T>(
    initialValue: T,
    private val validator: (T) -> Boolean
) : ReadWriteProperty<Any?, T> {
    
    private var value = initialValue
    
    override fun getValue(thisRef: Any?, property: KProperty<*>): T = value
    
    override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        require(validator(value)) { "Invalid value: $value" }
        this.value = value
    }
}

8.3 注意线程安全 #

kotlin
// lazy 默认是线程安全的
val value: String by lazy { compute() }

// 如果不需要线程安全
val valueFast: String by lazy(LazyThreadSafetyMode.NONE) { compute() }

九、总结 #

委托要点:

类型 语法 用途
类委托 by 继承替代
属性委托 by 属性逻辑
lazy by lazy 延迟初始化
observable Delegates.observable 监听变化
vetoable Delegates.vetoable 条件更新

下一步,让我们学习 协变与逆变

最后更新:2026-03-27