Kotlin에서는 동작 위임이 "by"라는 키워드의 언어적 메커니즘을 통해 클래스의 시그니처에서 직접 구현됩니다. 이는 인터페이스(또는 여러 인터페이스)의 메소드 호출을 다른 구현 객체로 자동 전달하여 보일러플레이트를 줄이고 조합을 쉽게 만듭니다.
인터페이스 위임의 출현은 다중 상속의 제한과 단점을 해결하려는 시도입니다. 이는 "상속보다 조합"이라는 아이디어로, 클래스 계층을 사용하지 않고 동작을 위임합니다. 조합이 더 일반적인 언어에서 차용되었습니다(예: Go, Scala).
Java 및 다른 언어에서는 종종 인터페이스를 만들고 각 메소드를 수동으로 구현하여 로직을 다른 필드로 전달해야 하며(Object Adapter 패턴), 이는 메소드 수가 증가할 때 빠르게 구식이 됩니다.
Kotlin은 "by"를 사용하여 인터페이스를 선언적으로 위임할 수 있습니다:
interface Logger { fun log(msg: String) } class ConsoleLogger: Logger { override fun log(msg: String) = println(msg) } class Service(logger: Logger): Logger by logger { fun doWork() { log("작업 시작") // ... } } val service = Service(ConsoleLogger()) service.doWork()
주요 특징:
Service 클래스에 동일한 시그니처를 가진 메소드를 추가하면 어떻게 됩니까?
자체 구현이 "위임을 덮어씁니다"—즉, 클래스에서 명시적으로 정의된 메소드가 우선합니다:
class Service(logger: Logger): Logger by logger { override fun log(msg: String) = println("PREFIX: $msg") }
하나의 클래스가 서로 다른 객체에 여러 인터페이스를 위임할 수 있습니까?
네, 클래스는 서로 다른 객체에 여러 인터페이스를 구현하고 위임할 수 있지만, 각 인터페이스는 하나의 객체에만 위임됩니다:
class Service( logger: Logger, tracker: Tracker ): Logger by logger, Tracker by tracker
인터페이스 위임과 by를 통한 속성 위임의 차이점은 무엇입니까?
클래스가 수동으로 인터페이스를 구현하고 각 메소드가 위임을 호출하며, 새로운 메소드가 추가될 때 프록시 업데이트를 잊어버려 오류가 발생합니다.
장점:
단점:
언어적 위임을 사용하고, 비표준 메소드만 클래스 내부에서 구현됩니다. 새로운 기능이 큰 수정 없이 추가됩니다.
장점:
단점: