문제의 배경:
"Delegation" 패턴은 많은 OOP 언어에서 알려져 있으며, 하나의 객체가 다른 객체에게 작업을 위임하는 원칙입니다. Java에서는 위임이 수동으로 구현되며 — 내부 필드와 메소드 프록시를 통해 이루어집니다. Kotlin에서는 by 키워드를 사용하여 위임이 문법 수준으로 가져와졌습니다.
문제:
Java에서 위임 패턴을 구현하면 복잡한 템플릿 코드로 과부하된 "신성한" 프록시 클래스가 발생하며, 인터페이스 지원에 많은 노력과 비용이 소요됩니다. 인터페이스 계약을 업데이트하고 위임자를 변경하는 것이 어렵습니다.
해결책:
Kotlin은 인터페이스를 직무적으로 구현하지 않고, class Foo(...) : MyInterface by delegateObj 형식을 사용하여 모든 메소드를 다른 객체에 위임하는 클래스를 생성할 수 있도록 허용합니다. 이렇게 하면 루틴을 없애고 유연성을 잃지 않으면서 간결하고 이해하기 쉬운 코드를 작성할 수 있습니다.
코드 예:
interface Base { fun print() } class BaseImpl(val x: Int) : Base { override fun print() = println(x) } class Derived(b: Base) : Base by b fun main() { Derived(BaseImpl(42)).print() // 42 }
주요 특징:
위임에도 불구하고 구현 클래스가 특정 메소드의 동작을 변경할 수 있습니까?
네 — 위임 클래스(Derived)에서 인터페이스 메소드를 명시적으로 구현하면 해당 메소드의 위임 동작을 "재정의"하게 됩니다.
예:
class Derived(b: Base) : Base by b { override fun print() = println("Overrided!") }
여러 인터페이스를 다른 객체에 동시에 위임할 수 있습니까?
아니요, Kotlin에서는 한 선언에서 여러 다른 인터페이스를 서로 다른 객체에 직접 위임할 수 없습니다. 수동 위임이 있는 클래스를 작성하거나 아키텍처가 허용하는 경우 상속과 위임을 조합해야 합니다.
위임은 추상 클래스와 함께 작동합니까, 아니면 인터페이스에만 해당합니까?
위임은 오직 인터페이스에 대해서만 가능하며, 추상 클래스는 상태와 protected 메소드가 있어 by를 통한 위임 선언과 호환되지 않기 때문에 위임할 수 없습니다.
개발자는 큰 인터페이스의 열 개 메소드를 위한 위임 패턴을 수동으로 구현합니다. 인터페이스가 확장될 때마다 새로운 프록시 메소드를 추가하는 것을 잊습니다. 코드가 커지고 버그가 발생합니다.
장점:
단점:
인터페이스의 자동 위임을 위해 by 문법을 사용했습니다. 구현을 쉽게 변경하고 위임자를 실시간으로 교체할 수 있으며, 계약 지원 시 실수를 할 위험이 줄어듭니다.
장점:
단점: