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

}

PrinterAPrinterB 모두 Printable을 구현하고 있습니다. 이 때, 두 클래스의 print() 메서드가 동일하기 때문에 각 클래스에서 메서드를 정의하는 것은 코드의 중복입니다.

이런 상황을 해결하기 위해 PrintableImpl라는 Printable의 구현 클래스를 만들고, PrintableImpl에서 PrinterAPrinterB에게 필요한 print() 메서드를 정의했습니다. 그 후 Printable by p를 이용해주면 각 클래스가 Printable의 구현을 p에게 위임할 수 있습니다. (pPrintableImpl 객체)

이 때, 두 클래스 모두 print() 메서드의 println(i)i값은 printableImpl 객체를 만들 때 생성자에게 준 10이 적용됩니다.

위 방법을 이용하면 PrinterAPrinterB가 각각 print()를 정의하지 않았기 때문에 중복된 코드도 없고, print() 메서드를 수정해야 하는 상황이 생기더라도 각 클래스에서 수정할 필요없이 PrintableImpl만 수정하면 됩니다.