
Delegation in Kotlin
📌 Delegation in Kotlin
Delegation is a design pattern in which one object delegates some responsibilities to another helper object. Kotlin provides delegation as a powerful feature using the by
keyword, making it easy to implement without writing boilerplate code.
🔎 Why Use Delegation?
Avoids code duplication.
Promotes code reuse.
Provides a flexible and cleaner design.
Useful in scenarios like interface implementation or object composition.
✅ 1. Types of Delegation in Kotlin
Kotlin supports two main types of delegation:
Interface Delegation → A class can delegate its functionality to another object using
by
.Property Delegation → Properties can delegate their getter and setter logic to another class using
by
.
✅ 2. Interface Delegation
📌 Example: Interface Delegation using by
interface Printer { fun ()}// Class implementing Printerclass ConsolePrinter : Printer { override fun () { println("Printing from ConsolePrinter") }}// Class using delegationclass SmartPrinter(printer: Printer) : Printer by printerfun () { val consolePrinter = ConsolePrinter() val smartPrinter = SmartPrinter(consolePrinter) smartPrinter.printMessage() // Output: Printing from ConsolePrinter}
🔎 Explanation:
SmartPrinter
usesby printer
to delegate theprintMessage()
call to theConsolePrinter
.This eliminates the need to implement the method manually.
✅ 3. Property Delegation
In Kotlin, you can delegate property accessors using the by
keyword. Commonly used delegates include:
lazy
observable
vetoable
🔎 a. Lazy Delegation
The
lazy
delegate initializes the value only when accessed for the first time.It is thread-safe by default.
val name: String by lazy { println("Initializing...") "John Doe"}fun () { println("Before accessing name") println(name) println(name) // Only initialized once}
Output:
Before accessing nameInitializing...John DoeJohn Doe
🔎 b. Observable Delegation
observable
allows you to track changes to a property.
import kotlin.properties.Delegatesvar count: Int by Delegates.observable(0) { _, oldValue, newValue -> println("Count changed from $oldValue to fun () { count = 10 count = 20}
Output:
Count changed from 0 to 10Count changed from 10 to 20
🔎 c. Vetoable Delegation
vetoable
allows you to reject changes based on a condition.
var age: Int by Delegates.vetoable(18) { _, _, newValue -> newValue >= 18}fun () { println("Initial Age: $age") age = Initial Age: 18Updated Age: 20After Invalid Update: 20
The assignment
age = 16
failed becausevetoable
rejected it.
✅ 4. Custom Delegation
You can create your own delegate by implementing the ReadOnlyProperty
or ReadWriteProperty
interfaces.
📌 Example: Custom Property Delegate
import kotlin.properties.ReadWritePropertyimport kotlin.reflect.KPropertyclass UpperCaseDelegate : ReadWriteProperty<Any?, String> { private var value: String = "" override fun (thisRef: Any?, property: fun (thisRef: Any?, property: fun main() { val person = Person() person.name = "john" println(person.name) // Output: JOHN}
🔎 Explanation:
Every time
name
is assigned a value, it is automatically converted to uppercase using the delegate.
✅ Conclusion
Interface Delegation using
by
reduces boilerplate code.Property Delegation is useful for lazy initialization, change observation, and conditional updates.
Custom Delegates provide additional flexibility by managing property behavior.