Kotlin's delegation pattern is a fundamental principle where an object delegates its functionality to another object. Kotlin supports delegation both at the class level (by delegating interfaces) and at the property level. This pattern is in line with the principle of composition over inheritance, offering a flexible alternative to inheriting behavior from a superclass.
Class Delegation
Kotlin allows class delegation using the by
keyword. When a class implements an interface, it can delegate the implementation of its methods to another object.
Example of Class Delegation:
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print() // Outputs 10
}
In this example, Derived
class doesn't implement the print
method itself but delegates it to an instance of BaseImpl
. When you call print
on an instance of Derived
, it internally calls print
on the BaseImpl
instance it holds.
Property Delegation
Kotlin supports property delegation, where a property's getter and setter can be delegated to a separate object, known as a delegate. The delegate is responsible for getting and setting the value. Property delegation is useful for encapsulating common patterns of property use, such as lazy initialization, observable properties, or storing properties in a map.
Example of Property Delegation:
import kotlin.reflect.KProperty
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("$value has been assigned to '${property.name}' in $thisRef.")
}
}
class Example {
var p: String by Delegate()
}
fun main() {
val e = Example()
println(e.p) // Calls getValue, which constructs a string
e.p = "NEW" // Calls setValue, which prints a message
}
In this property delegation example, the p
property of the Example
class is delegated to an instance of Delegate
. Whenever p
is accessed (getter) or modified (setter), the corresponding getValue
or setValue
method of Delegate
is called.
Benefits of Delegation in Kotlin
- Decoupling: Delegation allows separating the concerns of how a property is accessed or how an interface is implemented from the class that uses it.
- Reusable Code: Common patterns of property management, like lazy properties or observable properties, can be encapsulated in reusable delegates.
- Enhanced Control: Delegation provides more control over how properties are accessed and modified, enabling behaviors like validation, thread-safety, or logging when a property changes.
Kotlin's support for delegation simplifies many programming tasks and encourages composing objects in a way that promotes reusability and flexibility.