是否有更 DRY 的方式来使用 Kotlin Delegate 属性 observable?

Is there a more DRY way to use the Kotlin Delegate property observable?

我正在使用可观察模式来跟踪对象的变化。为此,我使用了来自 Kotlin 的 observable 中的构建。一切对我来说都很好,但为了跟踪一些变化,我必须为每个属性重复相同的代码。这是我的代码:

class Employee(
     id: String,
     name: String,
     surname: String,
     age: Int,
     salary: Int) {


     val changes = HashMap<String, Pair<Any, Any>>()


     val id = id //Id is immutable

var name: String by Delegates.observable(name) { prop, old, new ->
    if (old != new) {
        changes.put(prop.name, Pair(old, new))
        println("${prop.name} has changed from $old to $new")
    }
}

var surname: String by Delegates.observable(surname) { prop, old, new ->
    if (old != new) {
        changes.put(prop.name, Pair(old, new))
        println("${prop.name} has changed from $old to $new")
    }
}

var age: Int by Delegates.observable(age) { prop, old, new ->
    if (old != new) {
        changes.put(prop.name, Pair(old, new))
        println("${prop.name} has changed from $old to $new")
    }
}

var salary: Int by Delegates.observable(salary) { prop, old, new ->
    if (old != new) {
        changes.put(prop.name, Pair(old, new))
        println("${prop.name} has changed from $old to $new")
    }
 }

}

如您所见,我为每个属性重复了这些代码行:

by Delegates.observable(name) { prop, old, new ->
if (old != new) {
    changes.put(prop.name, Pair(old, new))
    println("${prop.name} has changed from $old to $new")
    }
 }

有没有人有想法让这段代码更干,这样我就不必到处复制和粘贴这些行,我确实在网上看过但找不到在别处定义逻辑并应用它的方法class 中的所有属性。

您不需要显式地重新声明这样的方法。您可以很容易地在 Kotlin 中传递方法引用。所以你可以这样做:

val age = Delegates.observable(age, ::handler) // Notice `::handler`
// repeat for the others...

// And this is the actual function:
fun handler(prop: KProperty<*>, old: Any, new: Any){
    if (old != new) {
        changes.put(prop.name, old to new)
        println("${prop.name} has changed from $old to $new")
    }
}

::handler 将方法引用传递给处理它们的方法。您仍然需要重复初始化,但不需要多次创建相同的处理程序方法。

此外,如果 id 是一个 val,而您不对它做任何事情,您可以这样做:

class Employee(
     val id: String, // Adding `val` or `var` in the constructor makes it an actual variable, instead of just local to the constructor. ***NOTE:*** This only applies to primary constructors. 
     name: String,
     surname: String,
     age: Int,
     salary: Int) {