Reputation:
I am using the observable pattern to track the changes in an object. To accomplish that I used the build in observable from Kotlin. Everything is working fine for me, butin order to track some changes I have to repeat the same code for every attribute. This is my code:
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")
}
}
}
As you can see I am repeating these lines of code for every attribute:
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")
}
}
Does anyone have an idea to make this code more DRY, so that I don't have to copy and paste the lines everywhere, I did look online but could not find a way to define the logic elsewhere and aply it to all attributes in the class.
Upvotes: 2
Views: 305
Reputation: 28228
You don't need to explicitly re-declare a method like that. You can pass method references in Kotlin quite easily. So you can do this:
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
passes a method reference to a the method that handles them all. You'll still need to repeat the initialization, but you don't need to create the same handler method multiple times.
Also, if id
is a val, and you don't do anything with it, you can just do this:
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) {
Upvotes: 0