Delgation 말 그대로 위임한다는 뜻이다.
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()
}
위의 코드의 결과는 10이다 Derived의 구현을 Base를 구현한 b에게 맡기고 b가 정의한 print()대로 출력된다.
interface Base {
fun printMessage()
fun printMessageLine()
}
class BaseImpl(val x: Int) : Base {
override fun printMessage() { print(x) }
override fun printMessageLine() { println(x) }
}
class Derived(b: Base) : Base by b {
override fun printMessage() { print("abc") }
}
fun main() {
val b = BaseImpl(10)
Derived(b).printMessage()
Derived(b).printMessageLine()
}
그럼 구현을 맡겨놓고 자기가 원하는 fun은 따로 구현을 한다면? 이것도 예상하기 쉽지만 자신이 override한 함수는 자신이 구현한 대로 출력된다. abc10이 출력된다.
interface Base {
val message: String
fun print()
}
class BaseImpl(val x: Int) : Base {
override val message = "BaseImpl: x = $x"
override fun print() { println(message) }
}
class Derived(b: Base) : Base by b {
// This property is not accessed from b's implementation of `print`
override val message = "Message of Derived"
}
fun main() {
val b = BaseImpl(10)
val derived = Derived(b)
derived.print()
println(derived.message)
}
그렇다면 이 코드는? 위임한 함수가 바라보는 message만 override 했다. 구현을 맡긴 print() 함수가 override한 message를 바라보는게 자연스러워 보이지만 위임한 함수는 위임한 클래스 내부의 값만 바라 볼 수 있다.
java로 decompile해서 살펴보면 위임한 Base 객체에서 print()를 호출하고 있는 것을 확인할 수 있다. 따라서 결과는
공식문서에 따르면 상속 대신에 위임 패턴을 통해서 필요한 부분만 재정의하여 사용하는 것이 좋은 대안이 되는 경우가 많다고 한다. 또한 kotlin에선 자체적으로 by 키워드를 통해 보일러 플레이트 코드를 피할 수 있다고 한다.