[Kotlin][Delegation] 2. Delegated Property

Choi Sang Rok·2022년 6월 21일
2

Kotlin

목록 보기
5/6
post-custom-banner

https://velog.io/@evergreen_tree/KotlinDelegation
이전 글에 이어서, 이번에는 Delegated Property에 대해 포스팅하겠습니다. KProperty 라는 생소한 개념도 나와서 함께 작성해 보았습니다.



📢Delegated Property


  • Class Delegation과 비슷하게 프로퍼티의 getter, setter를 다른 객체에 위임하는 것을 의미합니다.

Character라는 클래스에서 프로퍼티를 갱신하거나, 참조할 때 마다 값을 출력하는 상황을 예로 들어 보겠습니다.

class Character {
    var hp: Int = 0
        get() {
            println("Get hp : $field")
            return field
        }
        set(value) {
            println("Get hp : $value")
            field = value
        }

    var mp: Int = 0
        get() {
            println("Get hp : $field")
            return field
        }
        set(value) {
            println("Get mp : $value")
            field = value
        }
}

fun main() {
    val character = Character()
    character.hp = 100
    character.mp = 200
    println("캐릭터의 hp는 ${character.hp} mp는 ${character.mp}")
}

Character라는 클래스 내에서 접근자를 작성해주고, main에서 프로퍼티를 변경해 준 후 결과를 보겠습니다.

그리 복잡하지 않은 코드이지만, 이 다섯줄을 출력하기 위해 소비하는 코드가 너무 많습니다. 또한 중복된 내용을 담고 있습니다.
코드를 보면 접근자의 동작이 같은 형식을 띄고 있기에, 이를 따로 클래스에 담아서 수작업으로 위임해보겠습니다.

Delegation without by

class Delegator(private val name: String) {
    var value: Int = 0
    fun getter(): Int{
				println("get $name : $value")
        return value
    }
    fun setter(newValue: Int){
				println("set $name : $value")
        value = newValue
    }
}

class Character {
    var hpDelegator = Delegator("hp")
    var mpDelegator = Delegator("mp")

    var hp: Int
        get() = hpDelegator.getter()
        set(value) = hpDelegator.setter(value)

    var mp: Int
        get() = mpDelegator.getter()
        set(value) = mpDelegator.setter(value)
}

fun main() {
    val character = Character()
    character.hp = 100
    character.mp = 200
    println("캐릭터의 hp는 ${character.hp} mp는 ${character.mp}")
}


결과는 전과 똑같습니다.

총 코드 라인 수는 그렇게 달라지지 않았지만, Delegator에게 공통 형식의 접근자를 만들고 위임함으로써 재사용성이 올라갔습니다. 하지만 아직까지 중복되는 코드가 많아보입니다.

이제 코틀린의 by 키워드를 통해 이를 더 줄여보겠습니다.

Delegation using by

import kotlin.reflect.KProperty

class Delegator(private var value: Int) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
        println("get ${property.name} : $value")
        return value
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: Int) {
        println("set ${property.name} : $newValue")
        value = newValue
    }
}

class Character(hp: Int, mp: Int) {
    var hp by Delegator(hp)
    var mp by Delegator(mp)
}

fun main() {
    val character = Character(0,0)
    character.hp = 100
    character.mp = 200
    println("캐릭터의 hp는 ${character.hp} mp는 ${character.mp}")
}

Delegator클래스에서 연산자 오버로딩을 통해, getValuesetValue를 제공하게 되면, Character클래스의 hpmp에 접근자를 위임받아 사용할 수 있게 됩니다.

getValue와 setValue 라는 연산자 오버로딩을 구현하기 위해서는, 지정된 파라미터를 꼭 제공해야 합니다.

getValuesetValue
thisRef : 위임을 사용하는 클래스와 같은 타입이거나 Any 타입이어야 한다thisRef : 위임을 사용하는 클래스와 같은 타입이거나 Any 타입이어야 한다
property : Property<*>거나 Any 타입이어야 한다.property : Property<*>거나 Any 타입이어야 한다.
newValue : 위임을 사용하는 프로퍼티와 같은 타입이거나 Any 타입이어야 한다

Kproperty는 kotlin.reflect 패키지에 선언된 인터페이스로, val or var로 선언된 프로퍼티의 정보를 가지는 인터페이스입니다.

operator fun getValue(thisRef: Any?, property: KProperty<*>) {
        println("set ${property.name} : $newValue")
 }

만약 val hp라면 property.name 에서 “hp”에 대해 얻을 수 있습니다. KProperty의 인스턴스는 Reflection 연산자인 ::으로부터 얻을 수 있습니다.


Delegated Property를 통해, 보일러 플레이트 코드를 줄이고 코드의 재사용성을 늘릴 수 있겠군요!

참고 자료
https://kotlinlang.org/docs/delegation.html#overriding-a-member-of-an-interface-implemented-by-delegation

profile
android_developer
post-custom-banner

2개의 댓글

comment-user-thumbnail
2022년 6월 21일

메이플이 하고싶은거양..?

1개의 답글