跳转到内容

Kotlin委托

来自代码酷

Kotlin委托[编辑 | 编辑源代码]

Kotlin委托(Delegation)是一种强大的设计模式,允许一个对象将部分职责委托给另一个对象,从而减少代码重复并提高可维护性。Kotlin通过语言内置的`by`关键字简化了委托的实现,支持类委托和属性委托两种形式。

介绍[编辑 | 编辑源代码]

委托模式的核心思想是“组合优于继承”(Composition over Inheritance),即通过组合对象来实现功能复用,而不是通过继承。Kotlin的委托机制进一步优化了这一模式,使得开发者可以更简洁地表达委托关系。

类委托[编辑 | 编辑源代码]

类委托允许一个类将其公共方法的实现委托给另一个类的实例。Kotlin使用`by`关键字实现这一功能。

interface Base {
    fun print()
}

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

class Derived(b: Base) : Base by b  // 将Base接口的实现委托给b

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

解释: - `Derived`类通过`by`关键字将`Base`接口的实现委托给构造函数参数`b`。 - 调用`Derived(b).print()`时,实际执行的是`BaseImpl`的`print`方法。

属性委托[编辑 | 编辑源代码]

属性委托允许将属性的访问逻辑(`getter`/`setter`)委托给另一个对象。Kotlin标准库提供了`lazy`、`observable`等内置委托。

import kotlin.properties.Delegates

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

fun main() {
    val e = Example()
    e.name = "Alice"  // 输出: <no name> -> Alice
    e.name = "Bob"    // 输出: Alice -> Bob
}

解释: - `name`属性的修改会触发`observable`委托的回调,打印旧值和新值。

实际应用场景[编辑 | 编辑源代码]

1. 延迟初始化(Lazy Delegation)[编辑 | 编辑源代码]

`lazy`委托用于延迟初始化属性,直到首次访问时才计算其值。

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

fun main() {
    println(lazyValue)  // 输出: computed! \n Hello
    println(lazyValue)  // 输出: Hello(不再计算)
}

2. 观察属性变化(Observable Delegation)[编辑 | 编辑源代码]

`Delegates.observable`和`Delegates.vetoable`可用于监听属性变化或拦截赋值操作。

var positiveNumber: Int by Delegates.vetoable(0) { _, old, new ->
    new >= 0  // 仅当新值非负时才允许赋值
}

fun main() {
    positiveNumber = 10  // 成功
    println(positiveNumber)  // 输出: 10
    positiveNumber = -1     // 失败,值仍为10
}

3. 自定义委托[编辑 | 编辑源代码]

开发者可以通过实现`ReadOnlyProperty`或`ReadWriteProperty`接口创建自定义委托。

import kotlin.reflect.KProperty

class StringDelegate(private var value: String) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("访问属性 ${property.name}")
        return value
    }
    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) {
        println("修改属性 ${property.name}: $newValue")
        value = newValue
    }
}

class User {
    var name by StringDelegate("默认值")
}

fun main() {
    val user = User()
    println(user.name)  // 输出: 访问属性 name \n 默认值
    user.name = "Kotlin" // 输出: 修改属性 name: Kotlin
}

委托与继承的对比[编辑 | 编辑源代码]

classDiagram class Base { <<interface>> +print() } class BaseImpl { +print() } class Derived { -delegate: Base +print() via delegate } Base <|.. BaseImpl Base <|.. Derived Derived --> BaseImpl : 委托

优势: - 避免多重继承的复杂性。 - 运行时动态更换委托对象。

数学表达[编辑 | 编辑源代码]

委托可以形式化为: f(x)=g(h(x)) 其中: - h(x)是委托对象的方法。 - g是委托逻辑。

总结[编辑 | 编辑源代码]

Kotlin委托通过`by`关键字提供了一种简洁的方式实现: 1. 类委托:减少样板代码。 2. 属性委托:标准化属性访问逻辑。 3. 自定义委托:灵活扩展功能。

通过合理使用委托,可以显著提升代码的可读性和可维护性。