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