Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
  • 属性委托(by 关键字)

属性委托(by 关键字)

1. 什么是属性委托?

属性委托(Property Delegation)是 Kotlin 中一种强大的特性,允许将属性的 getter 和 setter 逻辑委托给另一个对象(称为委托对象)。通过 by 关键字实现,可以简化代码并实现逻辑复用。

核心思想

  • 解耦:将属性的存储或计算逻辑与类分离。
  • 复用:通过委托对象统一管理多个属性的行为(如延迟初始化、监听变化等)。

2. 基本语法

class Example {
    var property: Type by Delegate() // 委托给 Delegate 类的实例
}
  • 委托对象必须实现 ReadWriteProperty(可变属性)或 ReadOnlyProperty(只读属性)接口。

3. 自定义属性委托

示例:实现一个简单的委托

class SimpleDelegate(private var value: String) : ReadWriteProperty<Any?, String> {
    override fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("读取属性 ${property.name}")
        return value
    }

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        println("设置属性 ${property.name} 为 $value")
        this.value = value
    }
}

class User {
    var name: String by SimpleDelegate("默认值")
}

// 使用
fun main() {
    val user = User()
    println(user.name) // 输出:读取属性 name → "默认值"
    user.name = "Kotlin" // 输出:设置属性 name 为 Kotlin
}

4. 标准库中的委托属性

Kotlin 标准库提供了几种常用的委托实现:

4.1 lazy:延迟初始化

val lazyValue: String by lazy {
    println("首次访问时计算")
    "结果"
}

fun main() {
    println(lazyValue) // 输出:首次访问时计算 → "结果"
    println(lazyValue) // 直接返回缓存值 "结果"
}
  • 线程安全(默认使用 LazyThreadSafetyMode.SYNCHRONIZED)。

4.2 Delegates.observable:监听属性变化

import kotlin.properties.Delegates

var observedValue: Int by Delegates.observable(0) { _, old, new ->
    println("值从 $old 变为 $new")
}

fun main() {
    observedValue = 10 // 输出:值从 0 变为 10
}

4.3 Delegates.vetoable:拦截属性赋值

var maxValue: Int by Delegates.vetoable(0) { _, old, new ->
    new > old // 只有新值大于旧值时才允许赋值
}

fun main() {
    maxValue = 10
    println(maxValue) // 10
    maxValue = 5 // 赋值失败(无输出)
    println(maxValue) // 仍为 10
}

5. 使用场景与优势

  1. 延迟加载:减少资源消耗(如数据库连接、大对象初始化)。
  2. 观察者模式:自动响应属性变化(如 UI 更新)。
  3. 统一验证逻辑:集中管理属性的合法性检查。
  4. 简化代码:避免重复的 getter/setter 模板代码。

6. 注意事项

  • 委托对象的生命周期:需确保委托对象在属性访问期间有效。
  • 性能开销:委托可能引入额外的函数调用,但在大多数场景下可忽略。
  • 线程安全:自定义委托时需考虑并发访问问题。

7. 实战练习

尝试实现一个委托,要求:

  1. 属性值必须为非空字符串。
  2. 每次赋值时记录日志(包括时间戳)。

提示:结合 ReadWriteProperty 和 LocalDateTime 实现。

// 参考答案
class NonNullStringDelegate : ReadWriteProperty<Any?, String> {
    private var value: String = ""

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

    override fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        require(value.isNotEmpty()) { "属性值不能为空" }
        println("${LocalDateTime.now()} - 设置属性 ${property.name} 为 $value")
        this.value = value
    }
}
Last Updated:: 5/21/25, 7:58 PM