Kotlin 委托与扩展函数——新手入门

一、委托(Delegation)

1. 类委托

类委托允许将接口的实现委托给另一个对象,避免继承的局限性,适用于组合模式。

示例代码

kotlin 复制代码
interface Printer {
    fun printMessage(message: String)
}

class ConsolePrinter : Printer {
    override fun printMessage(message: String) {
        println("控制台输出: $message")
    }
}

// 通过委托将Printer接口的实现交给ConsolePrinter
class LogPrinter(printer: Printer) : Printer by printer {
    override fun printMessage(message: String) {
        println("日志记录开始")
        printer.printMessage(message)
        println("日志记录结束")
    }
}

fun main() {
    val consolePrinter = ConsolePrinter()
    val logPrinter = LogPrinter(consolePrinter)
    logPrinter.printMessage("测试消息")
}

使用场景

  • 需要增强或修改现有类的行为(装饰器模式)。
  • 避免多层继承带来的复杂性。

2. 属性委托

属性委托将属性的 getter/setter 逻辑委托给其他对象,Kotlin 标准库提供多种内置委托。

常用内置委托

  • lazy:延迟初始化属性。
  • observable:监听属性变化。
  • vetoable:在赋值前验证值。

示例代码

kotlin 复制代码
import kotlin.properties.Delegates

class Example {
    // 延迟初始化,首次访问时计算
    val lazyValue: String by lazy {
        println("计算lazyValue")
        "Hello, Lazy!"
    }

    // 监听属性变化
    var name: String by Delegates.observable("<未命名>") { _, old, new ->
        println("名称从 $old 更改为 $new")
    }

    // 仅允许非负数值
    var age: Int by Delegates.vetoable(0) { _, _, new ->
        new >= 0
    }
}

fun main() {
    val example = Example()
    println(example.lazyValue) // 输出:计算lazyValue \n Hello, Lazy!
    example.name = "Kotlin"    // 输出:名称从 <未命名> 更改为 Kotlin
    example.age = -5          // 赋值失败,age保持0
    println(example.age)       // 输出:0
}

使用场景

  • lazy:初始化成本高的资源(如数据库连接)。
  • observable:实现数据绑定或响应式UI更新。
  • vetoable:表单输入验证。

3. 自定义属性委托

通过实现 ReadWritePropertyReadOnlyProperty 接口创建自定义委托。

示例代码

kotlin 复制代码
import kotlin.reflect.KProperty

class FormatDelegate(private val format: String) : ReadWriteProperty<Any?, String> {
    private var value: String = ""

    override fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return value.format(format)
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        this.value = value
    }
}

class User {
    var username: String by FormatDelegate("用户名:%s")
}

fun main() {
    val user = User()
    user.username = "Alice"
    println(user.username) // 输出:用户名:Alice
}

使用场景

  • 统一格式化字符串、数值等属性。
  • 自动加密/解密敏感数据字段。

二、扩展函数(Extension Functions)

1. 基本用法

扩展函数允许为现有类添加新方法,无需继承或修改原始类。

示例代码

kotlin 复制代码
// 为String添加判断是否为有效邮件的扩展函数
fun String.isValidEmail(): Boolean {
    return matches(Regex("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}"))
}

// 为Int添加计算阶乘的扩展函数
fun Int.factorial(): Long {
    return if (this <= 1) 1 else this * (this - 1).factorial()
}

fun main() {
    println("user@example.com".isValidEmail()) // 输出:true
    println(5.factorial())                     // 输出:120
}

使用场景

  • 为第三方库或系统类添加实用方法。
  • 增强代码可读性,如 list.quickSort()

2. 扩展属性

类似扩展函数,可以为类添加"属性"(实际是计算属性,无幕后字段)。

示例代码

kotin 复制代码
val String.firstLetter: Char
    get() = if (isEmpty()) ' ' else this[0]

fun main() {
    println("Kotlin".firstLetter) // 输出:K
}

使用场景

  • 提供基于现有属性的快捷访问方式,如 file.extension

3. 扩展与成员冲突

当扩展函数与类成员函数同名时,成员函数优先。

示例代码

kotlin 复制代码
class Example {
    fun print() = println("成员函数")
}

fun Example.print() = println("扩展函数")

fun main() {
    Example().print() // 输出:成员函数
}

三、注意事项

1. 委托的可见性:

  • 委托对象需在类构造时初始化。
  • 避免在委托中持有外部类的引用导致内存泄漏。

2. 扩展的限制:

  • 无法访问类的私有成员。
  • 扩展是静态解析的,不具备多态性。

3. 性能考量:

  • lazy 委托默认是线程安全的,若不需要同步可用 lazy(LazyThreadSafetyMode.NONE) 提升性能。

四、总结

特性 适用场景 优势
类委托 组合优于继承、装饰器模式 减少重复代码,提升灵活性
属性委托 懒加载、属性监听、验证逻辑 逻辑复用,代码简洁
扩展函数 增强现有类功能、第三方库适配 无侵入式扩展,提高可读性
扩展属性 提供快捷访问属性 简化复杂计算逻辑的调用

合理运用委托和扩展函数,能显著提升Kotlin代码的简洁性和可维护性,但需注意避免滥用导致结构混乱。

更多分享

  1. 一文吃透Kotlin中冷流(Clod Flow)和热流(Hot Flow)
  2. 一文带你吃透Kotlin协程的launch()和async()的区别
  3. 一文带你吃透接口(Interface)结合 @AutoService 与 ServiceLoader 详解
  4. Kotlin 作用域函数(let、run、with、apply、also)的使用指南
  5. 一文带你吃透Kotlin中 lateinit 和 by lazy 的区别和用法
相关推荐
TeleostNaCl31 分钟前
如何安装 Google 通用的驱动以便使用 ADB 和 Fastboot 调试(Bootloader)设备
android·经验分享·adb·android studio·android-studio·android runtime
fatiaozhang95271 小时前
中国移动浪潮云电脑CD1000-系统全分区备份包-可瑞芯微工具刷机-可救砖
android·网络·电脑·电视盒子·刷机固件·机顶盒刷机
低调小一2 小时前
Swift 语法学习指南 - 与 Kotlin 对比
微信·kotlin·swift
2501_915918412 小时前
iOS 开发全流程实战 基于 uni-app 的 iOS 应用开发、打包、测试与上架流程详解
android·ios·小程序·https·uni-app·iphone·webview
lichong9512 小时前
【混合开发】vue+Android、iPhone、鸿蒙、win、macOS、Linux之dist打包发布在Android工程asserts里
android·vue.js·iphone
Android出海2 小时前
Android 15重磅升级:16KB内存页机制详解与适配指南
android·人工智能·新媒体运营·产品运营·内容运营
一只修仙的猿2 小时前
毕业三年后,我离职了
android·面试
编程乐学3 小时前
安卓非原创--基于Android Studio 实现的新闻App
android·ide·android studio·移动端开发·安卓大作业·新闻app
雅雅姐4 小时前
Android14 init.rc中on boot阶段操作4
android
fatiaozhang95274 小时前
中国移动中兴云电脑W132D-RK3528-2+32G-刷机固件包(非原机制作)
android·xml·电脑·电视盒子·刷机固件·机顶盒刷机