在 Kotlin 中,by
关键字用于实现委托模式(Delegation) ,它允许将某些操作或责任委托给另一个对象来处理。by
主要有两种用途:类委托 和属性委托。
1. 类委托(Class Delegation)
通过 by
关键字,可以将类的接口实现委托给另一个对象。这样可以在不继承的情况下复用现有类的功能。
示例:
kotlin
interface Animal {
fun makeSound()
}
class Dog : Animal {
override fun makeSound() {
println("Woof!")
}
}
// 通过 by 将 Animal 接口的实现委托给 dog 对象
class Robot(private val dog: Dog) : Animal by dog {
fun move() {
println("Robot is moving")
}
}
fun main() {
val dog = Dog()
val robot = Robot(dog)
robot.makeSound() // 实际调用的是 Dog 的 makeSound()
robot.move() // Robot 的独有方法
}
- 作用 :
Robot
类通过by dog
委托了Animal
接口的实现,无需手动重写makeSound()
。 - 优势:避免重复代码,优先组合而非继承。
2. 属性委托(Property Delegation)
通过 by
将属性的 getter/setter 逻辑委托给一个委托对象 (需实现 getValue()
和 setValue()
方法)。Kotlin 标准库提供了几种常用委托:
常见用途:
(1)懒加载委托 lazy
属性在首次访问时初始化。
kotlin
val heavyData: String by lazy {
println("Computing heavy data...")
"Heavy Result"
}
fun main() {
println(heavyData) // 第一次访问时计算并缓存
println(heavyData) // 直接返回缓存结果
}
(2)观察者委托 Delegates.observable
属性变化时触发回调。
kotlin
import kotlin.properties.Delegates
var name: String by Delegates.observable("Alice") { _, old, new ->
println("Name changed: $old -> $new")
}
fun main() {
name = "Bob" // 输出: Name changed: Alice -> Bob
}
(3)非空校验委托 Delegates.notNull
延迟初始化但确保非空。
kotlin
var age: Int by Delegates.notNull<Int>()
fun main() {
age = 30
println(age) // 必须先赋值,否则抛 IllegalStateException
}
(4)自定义委托
实现 ReadWriteProperty
或 ReadOnlyProperty
接口。
kotlin
class StringDelegate(private var value: String) {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
println("Getting value: $value")
return value
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: String) {
println("Setting value: $newValue")
value = newValue
}
}
var text by StringDelegate("Default")
fun main() {
println(text) // 输出: Getting value: Default
text = "New" // 输出: Setting value: New
}
关键点总结:
- 类委托 :通过
by
将接口实现委托给其他对象。 - 属性委托 :将属性的访问逻辑委托给
lazy
、observable
或自定义对象。 - 优势:减少重复代码,实现关注点分离(如懒加载、观察模式等)。
通过 by
,Kotlin 以简洁的语法实现了强大的委托模式,是 Kotlin 特色功能之一。