위임 프로퍼티1
Ref번역 - 의역 살짝(https://kotlinlang.org/docs/reference/delegated-properties.html#lazy)
위임 프로퍼티는 말그대로 위임 패턴을 적용한 프로퍼티이다.
우리는 보통 필요할 경우에 수동으로 accessor를 구현할 필요가 있는데 이 로직이 자주 쓰인다면 매번 구현할 것이 아니라 라이브러리에 넣고
쓴다면 좋을 것이다.
- Lazy 프로퍼티 : 첫 번째 acces시에만 값이 계산된다.
- 관찰 가능한 프로퍼티 : listeners들이 ㅍ로퍼티에 대한 변경 사항에 대한 알림을 받을수 있다.
- 각 프로퍼티에 대한 별도의 필드 대신 map에 각프로퍼티들을 저장한다.
이러한 (및 기타) 사례를 다루기 위해 Kotlin은 위임 된 속성을 지원합니다.
class Example {
var p: String by Delegate()
}
구문은 다음과 같다.
val / var <property name> : <Type> by <expression>
getValue () 및 setValue () 메서드에 위임 될 프로퍼티에 해당하는 get () (및 set ())이 by delegate이므로
by by expression
이 대리자이다.
프로퍼티 대리자는 인터페이스를 구현할 필요는 없지만 getValue () 함수 (및 vars의 경우 setValue () -)를 제공해야합니다. 예 :
class Delegate {
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.")
}
}
Delegate의 인스턴스에 delegate하는 p
를 읽을 때 Delegate
의 getValue()
함수가 호출되므로
첫 번째 매개 변수는 p에서 읽은 객체이고 두 번째 매개 변수는 p 자체에 대한 설명을 포함합니다 (예 : 이름을 가져 올 수 있습니다.) 예 :
val e = Example()
println(e.p)
출력 결과 :
com.kotlin.web.delegate.DelegateTest$Example@2752f6e2, thank you for delegating 'p' to me!
마찬가지로 p에 대입하면 setValue () 함수가 호출됩니다. 처음 두 매개 변수는 동일하고 세 번째 매개 변수는 할당 할 값을 보유합니다.
e.p = "NEW"
//노출 결과
NEW has been assigned to 'p' in com.kotlin.web.delegate.DelegateTest$Example@2752f6e2.
Kotlin 1.1에서는 함수 또는 코드 블록 내에 위임 된 속성을 선언 할 수 있으므로 반드시 클래스의 멤버가 아니어야합니다. 아래에서 예제를 찾을 수 있습니다.
Standard Delegates
Kotlin 표준 라이브러리는 몇 가지 유용한 대리인을위한 팩토리 메서드를 제공합니다.
Lazy
lazy()는 lamby를 취하고 lazy
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
fun main(args: Array<String>) {
println(lazyValue)
println(lazyValue)
}
This example prints:
computed! Hello Hello
기본적으로 게으른 속성의 평가는 동기화됩니다. 값은 하나의 스레드에서만 계산되며 모든 스레드는 동일한 값을 볼 수 있습니다. 초기화 대리자의 동기화가 필요하지 않아 여러 스레드가 동시에 실행할 수 있도록 LazyThreadSafetyMode.PUBLICATION을 매개 변수로 lazy () 함수에 전달합니다. 초기화가 항상 단일 스레드에서 발생한다고 확신하는 경우 스레드 안전성 보장 및 관련 오버 헤드가 발생하지 않는 LazyThreadSafetyMode.NONE 모드를 사용할 수 있습니다.
Observable
Delegates.observable ()은 초기 값과 수정을위한 핸들러라는 두 개의 인수를 취합니다. 처리기는 속성에 할당 할 때마다 (할당이 수행 된 후에) 호출됩니다. 세 개의 매개 변수가 있습니다 : 속성이 할당되고 이전 값과 새 값이 지정됩니다.
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}
fun main(args: Array<String>) {
val user = User()
user.name = "first"
user.name = "second"
}
This example prints:
<no name> -> first
first -> second
할당을 가로 채서 “거부”하려면 observable () 대신 vetoable ()을 사용하십시오. 거부권에 전달 된 핸들러는 새로운 속성 값의 할당이 수행되기 전에 호출됩니다.
Storing Properties in a Map
하나의 일반적인 사용 사례는 속성 값을지도에 저장하는 경우입니다. 이것은 JSON을 파싱하거나 다른 “동적 인”일을하는 것과 같은 애플리케이션에서 자주 발생합니다. 이 경우 위임 된 속성의 위임자로지도 인스턴스 자체를 사용할 수 있습니다.
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
In this example, the constructor takes a map:
val user = User(mapOf(
"name" to "John Doe",
"age" to 25
))
위임 된 속성은 이 맵에서 값을 가져옵니다 (문자열 키 - 속성 이름).
println(user.name) // Prints "John Doe"
println(user.age) // Prints 25
읽기 전용 Map 대신 MutableMap을 사용하면 var의 속성에도 적용됩니다.
class MutableUser(val map: MutableMap<String, Any?>) {
var name: String by map
var age: Int by map
}
Local Delegated Properties (since 1.1)
You can declare local variables as delegated properties. For instance, you can make a local variable lazy:
fun example(computeFoo: () -> Foo) {
val memoizedFoo by lazy(computeFoo)
if (someCondition && memoizedFoo.isValid()) {
memoizedFoo.doSomething()
}
}
The memoizedFoo variable will be computed on the first access only. If someCondition fails, the variable won’t be computed at all.