Kotlin Delegate - 3

홍승범·2023년 4월 30일
0

Kotlin

목록 보기
7/8

5. 대리자로서 Map 제공하기

  • 문제 : 여러 값이 들어있는 Map을 제공해 객체를 초기화 하고 싶다
    - 해법

    코틀린의 Map에는 대리자가 되는데 필요한 getValue, setValue함수 구현이 있다

    객체 초기화에 필요한 값이 맵 안에 있다면, 해당 클래스 속성을 자동으로 맵에 위임할 수 있다. 예를들면 아래와같은 Project클래스가 있다고 하자.

    data class Project(val map: MutableMap<String, Any?>) {
        val name: String by map
        val priority: Int by map
        val completed: Boolean by map
    }
    
    fun main() {
        val project = Project(mutableMapOf( "name" to "Learn Kotlin", "priority" to 5, "completed" to true))
        println(project.name)
        println(project.priority)
        println(project.completed)
    }

    객체의 변수이름과 같은 키가 매핑이 되어 위임된다.(거의 Decodable수준이다). 이 코드가 동작하는 이유는 MutableMap에 ReadWriteProperty 대리자가 되는 데 필요한 올바른 시그니처의 setValue, getValue확장함수가 있기 때문이다.

    	이게 필요한 이유를 예를 들어보면, 필요한 속성이 JSON 문자열에 있고, 이를 Gson을 이용해 파싱하여 그결과로 얻은 맵을 바로 Project로 생성할 수 있기 때문이다. 즉 아래와 같은 코드의 동작이 가능하다는것
    private fun getMapFromJson() = 
        Gson().fromJsonM<MutableMap<String, Any?>>(
            """{ "name":"Learn Kotlin", "priority":5, "completed": true } """,
            MutableMap::class.java
        )
    
    fun main() {
        val project = Project(getMapFromJson())
        println(project.name)
        println(project.priority)
        println(project.completed)
    }

6. 사용자 정의 대리자 만들기

  • 문제 : 어떤 클래스의 속성이 다른 클래스의 획득자와 설정자를 사용하게끔 만들고 싶다.
    - 해법

    ReadOnlyProperty, 또는 ReadWriteProperty를 구현하는 클래스를 생성함으로써 직접 속성 대리자를 작성한다.

    사용자 정의 속성 대리자를 생성하려면, ReadOnlyProperty, 또는 ReadWriteProperty인터페이스의 존재하는 함수를 제공해야 한다. 기본적으로는 그런데, 대리자를 만들기위해 인터페이스를 구현할 필요 없이 동일한 시그니처를 가진 setValue, getValue함수만 구현해주어도 된다.

    class MyDelegate {
        operator fun getValue(thisRef: Any?, property:KProperty<*>): String {
            return "$thisRef, thank you for delegating `${property.name}` to me!!!"
        }
    
        operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
            println("$value has been assigned to `${property.name}` in $thisRef")
        }
    }
    
    class Example {
        var p: String by MyDelegate()
    }
    
    fun main() {    val e = Example()
        println(e.p)
        e.p = "NEW"
    }

    위 코드에서 MyDelegate는 함수구현만 했을 뿐인데도, 위임자로서의 역할을 할 수 있으며 해당 코드의 실행 결과는 아래와 같다

    Example@22d8cfe0, thank you for delegating `p` to me!!!
    NEW has been assigned to `p` in Example@22d8cfe0
profile
그냥 사람

0개의 댓글