Kotlin 的 by 关键字用于实现委托模式,主要分为类委托和属性委托两种场景,以下是其核心机制与应用总结:
一、类委托
通过 by 将接口的实现委托给其他对象,避免手动编写重复代码:
interface Printer { fun print(message: String) }
class DefaultPrinter : Printer {
override fun print(message: String) { println(message) }
}
// 将 Printer 接口的实现委托给 printer对象 实例
class MyPrinter(printer: Printer) : Printer by printer
// 构建MyPrinter对象,实际调用的是实际调用 DefaultPrinter 的 print() 方法
val myPrinter = MyPrinter(DefaultPrinter()) myPrinter.print("Hello") //
- 原理:编译器自动生成接口方法的转发逻辑,调用直接委托给目标对象。
- 应用场景:简化装饰器模式实现,例如通过
by快速创建代理类。
上面的MyPrinter的写法等同于
// 传统的代理写法
class MyPrinter(private val printer: Printer) : Printer {
override fun print(message: String) {
printer.print(message)
}
}
二、属性委托
通过 by 将属性的读写操作委托给特定对象,典型应用包括延迟初始化、观察者模式等。
1. by lazy 延迟初始化
val viewModel by lazy {
FooApplication.pollingViewModel // 首次访问时初始化,后续直接返回缓存值
}
-
特性:
- 线程安全:默认同步锁(可通过
LazyThreadSafetyMode调整)34。 - 性能优化:避免高成本属性在未使用时初始化4。
- 线程安全:默认同步锁(可通过
-
底层实现:编译器生成双重检查锁代码,确保单次初始化。
2. 自定义属性委托
需实现 ReadOnlyProperty 或 ReadWriteProperty 接口:
class CustomDelegate<T> : ReadOnlyProperty<Any, T> {
override fun getValue(thisRef: Any, property: KProperty<*>): T { ... }
}
// 使用示例
val data by CustomDelegate<String>()
三、资源复用与解耦
委托模式通过组合替代继承,减少耦合:
class CountingSet<T>(private val innerSet: HashSet<T> = HashSet()) : Set<T> by innerSet {
var count = 0
override fun add(element: T): Boolean {
count++
return innerSet.add(element)
}
}
- 优势:不依赖
HashSet的具体实现,仅通过接口扩展功能。
四、注意事项
- 委托类与属性的独立性:
by仅转发接口方法或属性操作,不影响目标对象的其他功能。 - 适用场景:优先在需要代码复用、接口实现代理或复杂属性逻辑时使用,避免过度设计。
通过 by 关键字,Kotlin 以简洁语法实现委托模式,显著提升代码可维护性和灵活性。