코틀린에서는 인터페이스를 구현할 때 by 키워드를 이용해 인터페이스에 대한 구현을 다른 객체에 위임할 수 있습니다

 

예제

class CountingSet<T>(
    private val innerSet: MutableCollection<T> = HashSet(),
): MutableCollection<T> {
    override val size: Int = innerSet.size
    override fun contains(element: T): Boolean = innerSet.contains(element)
    override fun containsAll(elements: Collection<T>): Boolean = innerSet.containsAll(elements)
    override fun isEmpty(): Boolean = innerSet.isEmpty()
    override fun iterator(): Iterator<T> = innerSet.iterator()
    // ... 기타 수많은 메소드
}

set에 add한 횟수를 카운팅해서 저장하는 클래스를 만든다고 해보겠습니다

카운터를 만들기 전에, 아무 동작도 추가되지 않은 빈 껍데기 클래스를 만든다고 해도 위처럼 Collection 인터페이스의 메소드를 오버라이드 해줘야 합니다.

정작 오버라이드 하려는 add, addAll보다 boilerplate의 코드가 더 많습니다

 

class CountingSet<T>(
    private val innerSet: MutableCollection<T> = HashSet(),
): MutableCollection<T> by innerSet {
    private var counter = 0
    
    override fun add(element: T): Boolean {
        ++counter
        return innerSet.add(element)
    }

    override fun addAll(elements: Collection<T>): Boolean {
        counter += elements.size
        return innerSet.addAll(elements)
    }
}

by 키워드를 사용해 메소드 동작을 innerSet에 맡기면 이런식으로 다른 메소드의 동작을 위임시킬 수 있습니다

 

interface Movable {
    fun move(x: Int, y: Int)
}

interface Attackable {
    fun attack(target: Any)
}

class OnFoot : Movable {
    override fun move(x: Int, y: Int) = println("($x, $y)로 걸어감")
}

class WithGaussRifle : Attackable {
    override fun attack(target: Any) = println("${target}에게 가우스 소총 공격")
}

class WithFlameThrower : Attackable {
    override fun attack(target: Any) = println("${target}에게 화염방사기 공격")
}

class Marine : Movable by OnFoot(), Attackable by WithGaussRifle()
class Firebat : Movable by OnFoot(), Attackable by WithFlameThrower()

class HeroMarine(private val _marine: Marine) :
    Movable by _marine,
    Attackable by _marine {
    override fun attack(target: Any) {
        println("영웅마린의 공격!")
        return _marine.attack(target)
    }
}

위처럼 여러 인터페이스를 위임하는 것도 가능합니다 (https://stackoverflow.com/q/62685097/4295499)

 

Reference

- https://kotlinlang.org/docs/delegation.html

- https://en.wikipedia.org/wiki/Delegation_pattern

- Kotlin in Action 4.3.3