본문 바로가기

Language/Kotlin

코틀린[Kotlin]에서 Delegation 패턴 사용하기

Delegation

디자인 패턴에서 Delegate Pattern은 어떤 기능을 자신이 처리하지 않고 다른 객체에 위임을 시켜 그 객체가 일을 처리하도록 하는 것입니다. Delegate은 사전적 정의로 위임하다. 대표자 라는 뜻입니다.

 

Derived 클래스는 모든 public 멤버를 지정된 객체에 위임하여 Base 인터페이스를 구현할 수 있습니다.

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()
}

Derived의 상위 타입 목록에 있는 by 절은 b가 Derived의 객체에 내부적으로 저장되고 컴파일러가 b로 전달하는 Base의 모든 메서드를 생성함을 나타냅니다.

 

Kotlin에서 by 절을 사용하지 않은 Delegate Pattern은 print()메소드를 정의해야 합니다. 같은 코드를 다시 명시해야 하는 불편함이 생긴 것인데 by 절을 통해 중복된 코드를 제거할 수 있었습니다.

interface Base {
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override fun print() { print(x) }
}

class Derived(b: Base) : Base {
    val b: Base = b
    override fun print() { b.print() }
}

fun main() {
    val b = BaseImpl(10)
    Derived(b).print()
}

 

Delegation에 의해 구현된 인터페이스의 멤버 오버라이딩

오버라이딩는 예상대로 작동합니다. 컴파일러는 delegate 객체의(Base) 오버라이딩을 하는 것 대신 오버라이딩한 구현체를(위 예시에선 BaseImpl) 사용합니다.

override fun printMessage() { print("abc") } Derived로 재정의하면 프로그램은 printMessage가 호출될 때 10 대신 abc를 출력합니다.

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()
}

 

그러나 이러한 방식으로 재정의된 멤버는 인터페이스 멤버의 자신의 구현체에서만 접근할 수 있는 delegate 객체의 멤버에서 호출되지 않습니다.

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 {
    // message 프로퍼티는 b의 구현체인 BaseImpl에서 접근할 수 없다.
    override val message = "Message of Derived"
}

fun main() {
    val b = BaseImpl(10)
    val derived = Derived(b)
    derived.print()
    println(derived.message)
}