还有观察到的更干燥的方式来使用Kotlin委托属性吗?

时间:2018-11-08 10:21:42

标签: kotlin dry

我正在使用可观察的模式来跟踪对象中的更改。为此,我使用了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")
    }
 }

没有人有想法使此代码更干燥,这样我就不必在各处复制和粘贴行了,我的确在网上看过,但是找不到一种方法来定义其他地方的逻辑并适用于所有人类中的属性。

1 个答案:

答案 0 :(得分:1)

您不需要显式重新声明这样的方法。您可以很轻松地在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) {