티스토리 뷰

프로퍼티 위임

  • 클래스 위임과 비슷하게 프로퍼티의 값 설정(set)/가져오기(get)에서 위임을 사용할 수 있다.
  • 읽기 전용(val)일 경우에는 getValue()만 읽기/쓰기(var)가 가능할 경우 getValue()/setValue()를 구현한다.
  • by키워드를 이용하여 위임할 객체를 프로퍼티 뒤에 명시한다.
import kotlin.reflect.KProperty

class PropertyDelegate(var value: String) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        println("${property.name} get value ${this.value}")

        return value
    }

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

        this.value = newValue
    }
}

class Person {
    var name:String by PropertyDelegate("no name") // getValue, setValue
    val age: String by PropertyDelegate("31") // getValue
}

fun main() {
    val person = Person()
    // name get value no name
    println("person name is ${person.name}") // person name is no name

    person.name = "jin" // name set value no name -> jin
    // name get value no name
    println("person name is ${person.name}") // person name is jin

    // age get value 31
    println("person age is ${person.age}") // person age is 31
}
메서드 명 파라미터 명 설명
getValue() thisRef 위임을 사용하는 클래스와 같은 타입이거나 Any 타입이어야 한다.
property KProperty<*>거나 Any 타입이어야 한다.
setValue() thisRef 위임을 사용하는 클래스와 같은 타입이거나 Any 타입이어야 한다.
property KProperty<*>거나 Any 타입이어야 한다.
newValue 위임을 사용하는 프로퍼티와 같은 타입이거나 Any 타입이어야 한다.

표준 위임

코틀린 표준 라이브러리는 몇 가지 유용한 위임 객체를 위한 팩토리 메서드를 제공한다.

지연 초기화 - lazy

프로퍼티의 초기화를 객체 생성때 하지 않고 필요할 때 초기화하는 패턴

일반적으로 지연초기화를 코틀린에서 정의 할시 아래와같이 만들 수있다.

fun getPostListFromServer(id: Int): List<Post> {
    println("get big data from server")
    return listOf(Post())
}

class Post

class Board(val id: Int) {
    private lateinit var _list: List<Post>
    val list: List<Post>
        get() =
            if (!::_list.isInitialized) {
                println("lazy init")
                this._list = getPostListFromServer(this.id)
                this._list
            } else {
                println("already init")
                this._list
            }
}

fun main() {
    val board = Board(1)
    println("lazy init board list :: ${board.list}") // lazy init board list :: [Post@a09ee92]
    println("board list :: ${board.list}") // board list :: [Post@a09ee92]
}

// 실행 결과
// lazy init
// get big data from server
// lazy init board list :: [Post@a09ee92]
// already init
// board list :: [Post@a09ee92]

위의 방법을 lazy키워드를 사용하면 아래와 같이 간단하게 구현할 수 있다.

fun getPostListFromServer(id: Int): List<Post> {
    println("get big data from server")
    return listOf(Post())
}

class Post

class Board(val id: Int) {
    val list: List<Post> by lazy { getPostListFromServer(this.id) }
}

fun main() {
    val board = Board(1)
    println("lazy init board list :: ${board.list}") // lazy init board list :: [Post@a09ee92]
    println("board list :: ${board.list}") // board list :: [Post@a09ee92]
}

// get big data from server
// lazy init board list :: [Post@2f4d3709]
// board list :: [Post@2f4d3709]

관찰 및 거부권 - observable, vetoable

  • Delegates.observable() 은 초깃값과 수정에 대한 핸들러를 인자로 갖는다.
  • 프로퍼티에 값을 할당할 때마다 (할당 완료 후에) 핸들러를 호출한다.
import kotlin.properties.Delegates

class Person {
    var name: String by Delegates.observable("no name") { property, oldValue, newValue ->
        println("value change ($oldValue) to ($newValue)")
    }
}

fun main() {
    val person = Person()
    println("person name is ${person.name}")
    person.name = "jin"

    println("changed person name is ${person.name}")
}

// 실행 결과
// person name is no name
// value change (no name) to (jin)
// changed person name is jin

 

  • vetoable은 특정 조건이 맞지 않으면 값 설정을 거부한다.
import kotlin.properties.Delegates

class Person {
    // 200살 이상은 값 오류로 판단 값 셋팅을 거부한다.
    var age: Int by Delegates.vetoable(0) { property, oldValue, newValue ->
        newValue < 200
    }
}

fun main() {
    val person = Person()
    person.age = 31
    println("person age is ${person.age}") // person age is 31

    person.age = 9999 // 거부됨
    println("person age is ${person.age}") // person age is 31
}

맵에 프로퍼티 저장 - map

  • Json파싱과 같이 동적 작업을 할때 프로퍼티 값을 map에 저장하는 일은 비일비재하다.
  • map객체에 저장될 수 있게 by map으로 위임할 수 있다.
  • 읽기 전용(val)일시 map 읽기/쓰기(var)가 가능할시 mutable map을 사용한다.
class Person(map: MutableMap<String, Any>) {
    var name: String by map
    var age: Int by map
}

fun main() {
    val person = Person(mutableMapOf())
    person.name = "jin"
    person.age = 31

    println("person name is ${person.name} and age is ${person.age}") // person name is jin and age is 31
}

출처

https://javacan.tistory.com/entry/kotlin-11-12-ko-reference

 

코틀린 1.1 / 1.2 한글 레퍼런스 PDF 문서

코틀린 1.2 한글 레퍼런스 문서. 일부 내용(자바스크립트 관련 등)을 생략했고, 내용에 오류가 존재할 수 있음. 코틀린 1.1 한글 레퍼런스 문서. 일부 내용(자바스크립트 관련 등)을 생략했고, 내용에 오류가 존..

javacan.tistory.com

https://androidtest.tistory.com/113

 

22. 코틀린 위임 된 속성 (Delegated Properties) 알아보기

우리가 필요로 할 때마다 수작업으로 구현할 수 있지만 일반적으로 한 번만 구현하고 라이브러리에 넣는 것이 좋을 것입니다. 예 : 게으른 속성 : 첫 번째 액세스시에만 값이 계산됩니다. 관찰 가능한 속성 : 리스..

androidtest.tistory.com

http://blog.naver.com/PostView.nhn?blogId=yuyyulee&logNo=221380981114&parentCategoryNo=&categoryNo=22&viewDate=&isShowPopularPosts=true&from=search

 

[Kotlin 강좌] 20. 위임 프로퍼티 (Delegated Property) (2)

지난 포스팅에 이어 위임 프로퍼티가 유용하게 사용되는 몇 가지 기능에 대해 알아보자.by Lazy()'지연 초...

blog.naver.com

 

댓글