Delegate properties

Delegation refers to a situation in which we pass responsibility to someone else. In Kotlin, properties can either be accessed directly, or by using the get and set functions with the backing field. When properties are not backed by their own class but the responsibility is given to another class instead, these properties are called delegate properties. This might look strange at first, but when the class properties are more complex than simply storing values in fields, this feature becomes very convenient. First, let's have a look at how to delegate properties to the helper class. We'll start with a Person class with two properties, name and age:

class Person() {
val name : String by DelegatePersonName()
var age : Int by DelegatePersonAge()
}

There are two things to notice in the Person class: the by keyword and the class name after the by keyword. The by keyword shows that the name class property delegates its logic to the DelegatePersonName class. When we want to delegate the property, we need to implement the class that contains the following member functions:

  • getValue()
  • setValue()

For the immutable property, only the getValue function is required:

 class DelegatePersonName {
var value: String = "Default"

operator fun getValue(person: Person, property: KProperty<*>): String {
println("Property ${property.name}")
println(person.toString())
return value
}
}

class DelegatePersonAge {
var age : Int = 0
operator fun getValue(person: Person, property: KProperty<*>): Int {
return age
}
operator fun setValue(person: Person, property: KProperty<*>, i: Int) {
println("Class name: ${person}")
println("Property: ${property.name}")
age = i
}
}

Notice that the DelegatePersonAge class contains the getValue and setValue functions, which are actually operators. The getValue function, as its name suggests, returns the value when the property is being read, while the setValue function updates the property when a new value is assigned to the class property. In each class, we need to declare a backing field. For the DelegatePersonAge class, we have created a property called age, while for the DelegatePersonName class, we have created a property called value.

The setValue and getValue functions take two parameters: the first parameter is the type of class that can use this delegated property, and the second parameter indicates which value type will be passed to the function. If we pass property.name to the print function, it will display the name of the property, the name for the DelegatePersonName class, and the age for the DelegatePersonAge class.

After that, create an instance of the class and perform some read and write tasks:

fun main(args: Array<String>) {
val person = Person()
println(person.name)
println(person.age)
person.age = 40
println(person.age)
}

Notice that the getValue function from the delegated class is triggered when the property is read. The setValue function is called when the value is assigned to the property.

We can create a generic delegate that can work for any data type:

class DelegateGenericClass {
private var value: Any = "Not initialized"
operator fun getValue(instance: Any, property: KProperty<*>): Any {

println("Class name : ${instance}")
println("property name : ${property.name}")
return value
}

operator fun setValue(instance: Any, property: KProperty<*>, type: Any) {
value = type
}
}

Create a class called DelegateGenericClass and declare a backing field value of the Any type. Declare the getValue function with a first parameter of the Any class and a return type of Any as well. Do the same with the setValue function. Now, create two classes, Person and Student, declare one property in each class (the address property in the Person class and the age property in the Student class) and delegate these properties to the generic class:

class Person{
var address: Any by DelegateGenericClass()
}

class Student{
var age : Any by DelegateGenericClass()
}

Create an instance of the Person class and assign a string value to the address. After that, create an instance of the Student class and assign an integer value to it:

fun main(args: Array<String>) {
val person = Person()
person.address = "Stockholm City"
println("Address "+person.address)

val student = Student()
student.age = 40
println("Age " +student.age)
}

Notice that we have assigned a different type of value to each property but the generic delegate class works for both.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.229.44