Skip to main content

by keyword

When to use

Required delegating implements of interface or inheritance of abstract class to another object.

Why to use

Enhance re-usability and reducing the amount of code.

How to use

I'll introduce a SmartPhone class consists of Phone and Camera.
So this is composition relation.

info

In recent, OOP prefers composition than inheritance.

Interface

interface Phone {
fun dial(phoneNumber: String) : String
}

Implements

class DefaultPhone : Phone {
override fun dial(phoneNumber: String): String {
return "Dialing $phoneNumber.."
}
}

Client

Using by keyword, we can delegate implementation to camera and phone object.
No need implements in SmartPhone class.

class SmartPhone (
private val camera: Camera = DefaultCamera(),
private val phone: Phone = DefaultPhone()
) : Camera by camera, Phone by phone

Delegates singleton object

vetoable

We can limit the change the value using by keyword and Delegates.vetoable()

SmartPhone.kt

class SmartPhone (
private val camera: Camera = DefaultCamera(),
private val phone: Phone = DefaultPhone()
) : Camera by camera, Phone by phone {
// initial value is 1
var serialNumber : Int by Delegates.vetoable(1){property, oldValue, newValue ->
// only true if range in [1,10]
newValue in 1 .. 10
}
}

SmartPhoneTest.kt

class SmartPhoneTest {
private val smartPhone = SmartPhone()

@DisplayName("시리얼 초기값 검사")
@Test
internal fun testSerialNumberInitValue() {
assertEquals(1, smartPhone.serialNumber)
}

@DisplayName("시리얼넘버 변경 감지")
@Test
internal fun testSerialNumberChange() {
smartPhone.serialNumber = 11
// failed to change to 11 range 1..10
assertNotEquals(11, smartPhone.serialNumber)
}
}

observable

If you want only capturing changing. Use Delegates.observable()
This doesn't return anything (Unit)

SmartPhone.kt

class SmartPhone (
private val camera: Camera = DefaultCamera(),
private val phone: Phone = DefaultPhone()
) : Camera by camera, Phone by phone {
// initial value is 1
var serialNumber : Int by Delegates.observable(1) {property, oldValue, newValue ->
println("${property.name} changed from $oldValue to $newValue")
}
}

Reference

delegation - kotlin docs