Kotlin 属性委托 observable 的实现原理

Kotlin 的 Delegates.observable 是 Kotlin 标准库中提供的一个属性委托,它允许你在属性的值发生变化时自动执行某段逻辑,比如常用于监听属性变化(例如 UI 数据更新)。

基本使用示例:

kotlin 复制代码
import kotlin.properties.Delegates

var name: String by Delegates.observable("initial") { property, oldValue, newValue ->
    println("${property.name} changed from $oldValue to $newValue")
}

fun main() {
    name = "Alice"
    name = "Bob"
}

输出:

css 复制代码
name changed from initial to Alice
name changed from Alice to Bob

实现原理

1. Delegates.observable(...) 返回了一个实现了 ReadWriteProperty 接口的对象:

kotlin 复制代码
public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
            ReadWriteProperty<Any?, T> =
        object : ObservableProperty<T>(initialValue) {
            override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
        }

它返回了一个 ObservableProperty 实例。

2. ObservableProperty 实现了属性委托接口ReadWriteProperty

kotlin 复制代码
public abstract class ObservableProperty<V>(initialValue: V) : ReadWriteProperty<Any?, V> {
    private var value = initialValue

    protected open fun beforeChange(property: KProperty<*>, oldValue: V, newValue: V): Boolean = true

    protected open fun afterChange(property: KProperty<*>, oldValue: V, newValue: V): Unit {}

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

    public override fun setValue(thisRef: Any?, property: KProperty<*>, value: V) {
        val oldValue = this.value
        if (!beforeChange(property, oldValue, value)) {
            return
        }
        this.value = value
        afterChange(property, oldValue, value)
    }

    override fun toString(): String = "ObservableProperty(value=$value)"
}

beforeChange在属性值被变更前被调用,默认返回true,就是说即使你写出这样的代码:

kotlin 复制代码
import kotlin.properties.Delegates

var name: String by Delegates.observable("init") { property, oldValue, newValue ->
    println("${property.name} changed from $oldValue to $newValue")
}

fun main() {
    name = "init"
    name = "Bob"
}

也会输出结果:

csharp 复制代码
name changed from init to init
name changed from init to Bob

ObservableProperty内部维护了属性值,并在 setValue 方法中触发回调,这个回调的实现就是我们传入的lambda参数onChange

每次我们通过赋值等操作修改被委托的属性时,都会触发 setValue() 方法,从而调用 onChange 回调。

总结:工作机制

  1. Delegates.observable(initialValue, onChange) 返回 ObservableProperty 实例
  2. ObservableProperty 实现了 ReadWriteProperty 接口
  3. Kotlin 编译器在 by 后会将属性访问转发给 getValue()setValue()
  4. setValue() 中自动触发 onChange() 回调

使用场景

  • 数据绑定(如 UI)
  • 表单输入监听
  • MVVM 架构中 ViewModel 属性监听
  • 日志审计、调试属性变化等
相关推荐
Jackson__14 小时前
为什么 Agent 越聊越慢?聊聊 Context(上下文)管理
前端·agent·ai编程
KaMeidebaby14 小时前
卡梅德生物技术快报|抗体合成:多肽抗体合成工程化方案:Nsp2 保守肽多抗制备与多维度验证
前端·网络·数据库·人工智能·算法
青禾网络14 小时前
前端做音画匹配这件事,我从"随机塞"到"AI 自动对齐"
前端·github
2601_9637713715 小时前
Hardening Enterprise WordPress Sites Against REST API Leaks and Bad Headers
前端·windows·word·php
蓝银草同学15 小时前
Stream 实战:博客列表排序、过滤与分页(AI 辅助学习 Java 8)
java·前端·后端
2601_9571909015 小时前
飞行影院安装施工指南:场地、动感系统与影片内容配套
大数据·前端·人工智能
爱折腾的小黑牛15 小时前
简记往来批量录入功能的实现:从文本到结构化数据
前端·算法
YHHLAI16 小时前
Agent 智能体开发实战 · 第六课:MCP 协议 —— 让 Agent 跨进程调用工具
前端·人工智能
SmartBoyW16 小时前
前端死磕:一文彻底搞懂 JS 事件循环 (Event Loop) 与宏微任务
前端·javascript
爱勇宝16 小时前
3位工程师靠“删AI代码”创业,一周收费1万美元:以后最贵的能力,可能不是写代码
前端·后端·架构