이동식 저장소

[Kotlin] 위임 본문

Primary/Kotlin

[Kotlin] 위임

해스끼 2021. 1. 6. 11:52

위임이란 어떤 클래스의 멤버를 참조 없이 호출하고 싶을 때 사용하는 선언 방식이다. 

클래스의 위임

다음의 코드를 보자.

// 1
interface Animal {
    fun eat()
}
// 2
class Cat : Animal {
    override fun eat() {
        println("eat() at Cat")
    }
}
// 3
val cat = Cat()
// 4
class Robot : Animal by cat
  1. 인터페이스 ``Animal``을 정의하였다.
  2. 클래스 ``Cat``을 선언하고, ``Animal``을 구현하였다. ``Cat``은 추상 클래스 또는 인터페이스가 아니므로 ``eat()``을 정의해야 한다.
  3. ``Cat``의 객체 ``cat``을 만들었다.
  4. 클래스 ``Robot``을 선언하고, ``Animal``을 구현하였다. ``Robot`` 역시 ``eat()``을 정의해야 할 것 같지만, ``by`` 키워드를 사용하여 ``cat``에게 정의를 위임한다.

즉 ``Robot``은 ``eat()``을 직접 구현하는 대신 ``cat``의 ``eat()``을 대신 사용하는 것이다. 자바 바이트코드를 디컴파일해 보면 ``Robot``에도 ``cat``의 ``eat()``이 구현되어 있음을 확인할 수 있다.

위임받은 객체의 eat()을 호출한다.

위임을 왜 쓸까?

코틀린의 기본 라이브러리는 상속할 수 없도록 정의되어 있다. 실제로 ``List`` 등의 클래스는 모두 ``open``이 아니다. 이렇게 함으로써 라이브러리의 무분별한 상속을 막을 수 있지만, 클래스의 기능을 확장하기 어려워지는 문제가 발생한다.

 

위임을 사용하면 실제로 상속하지는 않지만 상속과 비슷한 효과를 낼 수 있다. 즉 클래스의 모든 기능을 사용하는 동시에 기능을 추가로 구현할 수 있다. 다만 강의에서 예시가 주어지지 않아 정확한 코드는 잘 모르겠다.

클래스의 위임 예시

interface Animal {
    fun eat(): String
}

class Cat : Animal {
    override fun eat() = "eat() at Cat"
}

class Dog : Animal {
    override fun eat() = "eat() at Dog"
}

class AnimalModel(private val name: String, anim: Animal) : Animal by anim {
    fun animalInfo() {
        println("name: $name, eat: ${eat()}")
    }
}

fun main() {
    val dog = AnimalModel("doge", Dog())
    val cat = AnimalModel("nangman", Cat())
    dog.animalInfo()
    cat.animalInfo()
}

위임받은 클래스의 ``eat()`` 메소드가 실행되었음을 볼 수 있다.

Observable

프로퍼티의 값이 변경될 때 특정 함수를 호출한다.

class Person {
    // 초기값: 0
    var age: Int by Delegates.observable(0) { prop, old, new ->
        println("age: $old -> $new")
    }
}

fun main() {
    val me = Person()
    me.age = 22
    me.age = 23
}

유용하게 써먹을 수 있지 않을까? 값을 변경할 때마다 로그를 찍는다던가.

Vetoable

값을 갱신할 때, 조건에 맞지 않으면 갱신을 거부(veto)할 수 있다. 비토권 할 때의 veto 맞다.

fun main() {
    // 초기값 설정 가능(여기서는 0)
    var max: Int by Delegates.vetoable(0) { prop, old, new ->
        new > old
    }

    max = 50
    println("max: $max")

    max = 10 // veto!
    println("max: $max")
}

람다식이 ``true``를 반환할 때만 값이 갱신된다. ``old``는 이전 값, ``new``는 새로 갱신하려는 값이다.

참고 문헌

Do it! Kotlin programming @ edwith boostcourse

 

코틀린 프로그래밍 기본 2/2(객체지향편)

부스트코스 무료 강의

www.boostcourse.org

Delegated Properties @ Kotlin

 

Delegated Properties - Kotlin Programming Language

 

kotlinlang.org

 

'Primary > Kotlin' 카테고리의 다른 글

[Kotlin] Coroutines - Basics  (0) 2021.01.19
[Kotlin] Sequence  (0) 2021.01.15
[Kotlin] Thread 생성 및 실행  (0) 2021.01.14
[Kotlin] Collections 확장 함수  (0) 2021.01.13
[Kotlin] 데이터 클래스  (0) 2021.01.08
Comments