개발 언어/코틀린
코틀린(Kotlin) | 프로퍼티 위임
jjiiiinn
2019. 6. 24. 16:43
728x90
프로퍼티 위임
- 클래스 위임과 비슷하게 프로퍼티의 값 설정(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
https://androidtest.tistory.com/113
728x90