Careeroza
Class Delegation
Composition Without Boilerplate
Delegation means "let another object do the work". With class A(b: B) : Interface by b the compiler generates every interface method and forwards it to b. You override only what you want to change. It is the decorator pattern without writing forwarding code, and a clean alternative to inheritance.
Example
A list that counts how many items were added, without extending ArrayList.
class CountingList<T>(
private val inner: MutableList<T> = mutableListOf(),
) : MutableList<T> by inner {
var addCount = 0
private set
override fun add(element: T): Boolean {
addCount++
return inner.add(element)
}
override fun addAll(elements: Collection<T>): Boolean {
addCount += elements.size
return inner.addAll(elements)
}
}
fun main() {
val list = CountingList<String>()
list.add("Kotlin")
list.addAll(listOf("Java", "Go"))
list.remove("Go") // forwarded automatically
println("List: ${list.toList()}, size: ${list.size}") // toString() is not delegated
println("Items ever added: ${list.addCount}")
}Output
List: [Kotlin, Java], size: 2 Items ever added: 3
Decorating a Service
Example
Add logging around any PaymentGateway implementation.
interface PaymentGateway {
fun pay(orderId: String, amount: Int): String
fun refund(orderId: String): String
}
class RazorpayGateway : PaymentGateway {
override fun pay(orderId: String, amount: Int) = "paid Rs $amount for $orderId"
override fun refund(orderId: String) = "refunded $orderId"
}
class LoggingGateway(private val target: PaymentGateway) : PaymentGateway by target {
override fun pay(orderId: String, amount: Int): String {
println("LOG: pay($orderId, $amount)")
return target.pay(orderId, amount)
}
}
fun main() {
val gateway: PaymentGateway = LoggingGateway(RazorpayGateway())
println(gateway.pay("ORD-1", 799))
println(gateway.refund("ORD-1")) // not logged: plain forwarding
}Output
LOG: pay(ORD-1, 799) paid Rs 799 for ORD-1 refunded ORD-1
Tip: "Prefer composition over inheritance" (Effective Java, item 18). Kotlin classes are final by default, and by makes composition as short as inheritance.