Kotlin 的委托特性

317 阅读2分钟

Kotlin 的委托(Delegation)特性通过语法层面的支持,简化了委托模式的实现,分为‌类委托‌和‌属性委托‌两种核心形式。以下是详细解析:


一、类委托

通过 by 关键字将接口或抽象类的实现委托给其他对象,避免继承的局限性。

1. ‌基本语法

interface Base {
    fun print()
}

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

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

调用时:

val b = BaseImpl(10)
Derived(b).print()  // 输出 10:ml-citation{ref="3,4" data="citationList"}

编译器会自动生成 Base 接口的所有方法,并转发调用至 b 对象。

2. ‌优势

  • 替代继承‌:解决单继承限制,避免多层继承的复杂性1。
  • 减少模板代码‌:无需手动重写接口方法,自动委托实现46。

二、属性委托

将属性的读写逻辑委托给另一个对象,常用于统一管理属性或实现延迟加载等功能。

1. ‌基本语法

class Delegate {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return "委托返回值"
    }
    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("设置值为 $value")
    }
}

class Example {
    var p: String by Delegate()  // 委托属性 p
}

使用:

val example = Example()
example.p = "新值"  // 调用 Delegate.setValue()
println(example.p)  // 调用 Delegate.getValue(),输出 "委托返回值":ml-citation{ref="2,5" data="citationList"}

2. ‌规则

  • 方法签名‌:委托类需实现 getValue()val 属性)或 getValue() + setValue()var 属性)。

  • 参数含义‌:

    • thisRef:委托属性的持有对象。
    • property:属性元信息(通过反射获取)57。

三、内置委托工具

Kotlin 标准库提供常用委托实现:

1. ‌延迟属性(Lazy)

val num: Int by lazy { 
    println("首次访问时初始化")
    100 
}
println(num)  // 输出 "首次访问时初始化" 和 100
  • 线程安全‌:默认使用 LazyThreadSafetyMode.SYNCHRONIZED8。

2. ‌可观察属性(Observable)

import kotlin.properties.Delegates

var name: String by Delegates.observable("默认值") { 
    _, old, new -> println("从 $old 变为 $new") 
}
name = "新名字"  // 触发回调,输出 "从 默认值 变为 新名字":ml-citation{ref="4,8" data="citationList"}

四、委托的应用场景

  1. 代码复用‌:将通用逻辑(如属性存储、监听)封装至委托类。
  2. 解耦‌:分离核心逻辑与辅助功能(如日志、缓存)27。
  3. 简化复杂操作‌:如通过委托实现属性与 SharedPreferences 的绑定5。

五、委托 vs 继承

特性委托继承
代码复用方式组合对象父子类关系
多态支持通过接口实现直接继承
灵活性更高(可动态替换委托对象)较低(静态绑定)
适用场景需要横向扩展或避免继承链复杂化时严格的“is-a”关系时

六、注意事项

  • 委托类方法可见性‌:需确保 getValue()/setValue() 对委托属性可见(如定义为 public 或同模块)7。
  • 性能影响‌:属性委托可能引入额外对象,需权衡代码简洁性与性能开销2。