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"}
四、委托的应用场景
- 代码复用:将通用逻辑(如属性存储、监听)封装至委托类。
- 解耦:分离核心逻辑与辅助功能(如日志、缓存)27。
- 简化复杂操作:如通过委托实现属性与 SharedPreferences 的绑定5。
五、委托 vs 继承
| 特性 | 委托 | 继承 |
|---|---|---|
| 代码复用方式 | 组合对象 | 父子类关系 |
| 多态支持 | 通过接口实现 | 直接继承 |
| 灵活性 | 更高(可动态替换委托对象) | 较低(静态绑定) |
| 适用场景 | 需要横向扩展或避免继承链复杂化时 | 严格的“is-a”关系时 |
六、注意事项
- 委托类方法可见性:需确保
getValue()/setValue()对委托属性可见(如定义为public或同模块)7。 - 性能影响:属性委托可能引入额外对象,需权衡代码简洁性与性能开销2。