Kotlin에는 by
라는 키워드가 있습니다. by
는 클래스 위임을 위한 키워드 입니다.
클래스 위임이란 어떤 클래스가 어떤 인터페이스를 구현하는 상황에서, 그 인터페이스의 메서드들을 직접 구현하지 않고, 다른 클래스에게 위임해 그 클래스의 구현을 그대로 사용하는 것 입니다.
이 방식은 다른 클래스를 상속하는 대신 사용할 수 있습니다. 상속과의 차이점은 인터페이스가 갖는 메서드 이외의 메서드들은 상속 받지 않기 때문에 필요한 메서드들만 상속 받을 수 있다는 것 입니다.
클래스 위임의 특징은 다음과 같습니다.
- 인터페이스의 정의 필요
open
키워드 없이 클래스를 상속- 위임할 클래스의
private
변수에 접근 불가 - 상속과 다르게 여러 클래스 위임 가능
- 아래는
by
를 이용한 예시 코드입니다.
interface Printable {
fun print()
}
class PrintableImpl(private val i: Int): Printable {
override fun print() { println(i) }
}
class PrinterA(p: PrintableImpl): Printable by p {
fun printModel() { println("Printer Model A") }
}
class PrinterB(p: PrintableImpl): Printable by p {
fun printModel() { println("Printer Model B") }
}
fun main() {
val printableImpl = PrintableImpl(10)
val printerA = PrinterA(printableImpl)
printerA.printModel()
printerA.print()
val printerB = PrinterB(printableImpl)
printerB.printModel()
printerB.print()
}
PrinterA
와 PrinterB
모두 Printable
을 구현하고 있습니다. 이 때, 두 클래스의 print()
메서드가 동일하기 때문에 각 클래스에서 메서드를 정의하는 것은 코드의 중복입니다.
이런 상황을 해결하기 위해 PrintableImpl
라는 Printable
의 구현 클래스를 만들고, PrintableImpl
에서 PrinterA
와 PrinterB
에게 필요한 print()
메서드를 정의했습니다. 그 후 Printable by p
를 이용해주면 각 클래스가 Printable
의 구현을 p
에게 위임할 수 있습니다. (p
는 PrintableImpl
객체)
이 때, 두 클래스 모두 print()
메서드의 println(i)
의 i
값은 printableImpl
객체를 만들 때 생성자에게 준 10이 적용됩니다.
위 방법을 이용하면 PrinterA
와 PrinterB
가 각각 print()
를 정의하지 않았기 때문에 중복된 코드도 없고, print()
메서드를 수정해야 하는 상황이 생기더라도 각 클래스에서 수정할 필요없이 PrintableImpl
만 수정하면 됩니다.