Kotlin中的by

435 阅读2分钟

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 的具体实现,仅通过接口扩展功能‌。

四、注意事项

  1. 委托类与属性的独立性by 仅转发接口方法或属性操作,不影响目标对象的其他功能‌。
  2. 适用场景:优先在需要代码复用、接口实现代理或复杂属性逻辑时使用,避免过度设计‌。

通过 by 关键字,Kotlin 以简洁语法实现委托模式,显著提升代码可维护性和灵活性。