처음 사용하는 요청이 들어올 때 초기화 되는 프로퍼티
val value by lazy { createValue() }
변화가 있을 때 이를 감지하는 observable 패턴, stdlib의 observable 델리게이트 기반으로 구현 가능
var items: List<Item> by Delegates.observable(listOf()) { _, _, _ ->notifyDataSetChanged() }var key: String? by Delegates.observable(null) { _, old, new -> Log.e("Key changed from new $old to $new") }
프로퍼티 위임 메커니즘을 활용하면, 다양한 패턴들을 간단하고 type-safe하게 만들 수 있음
프로퍼티 위임을 통한 getter, setter 로깅
프로퍼티 위임은 다른 객체의 메소드를 활용해서 프로퍼티의 접근자(게터와 세터)를 만드는 방식
이때 다른 객체의 메소드 이름이 중요함
게터는 getValue, 세터는 setValue 함수를 사용해서 만들어야 한다.
객체를 만든 뒤에는 by 키워드를 사용해서, getVlaue와 setValue를 정의한 클래스와 연결해 주면 된다.
classLoggingProperty<T>(varvalue: T) {operatorfungetValue( thisRef: Any?, prop: KProperty<*> ): T {println("${prop.name} returned vale $value")returnvalue }operatorfunsetValue( thisRef: Any?, prop: KProperty<*>, newValue: T ) {val name = prop.nameprintln("$name changed from $value to $newValue")value= newValue }}funmain() {var tokenaaa: String? byLoggingProperty(null)var attempts: IntbyLoggingProperty(0) tokenaaa tokenaaa ="a" attempts attempts =1}
프로퍼티 위임이 어떻게 동작하는지 이해하려면, by가 어떻게 컴파일되는지 보는 것이 좋다. 위와 같은 코드는 아래와 비슷하게 컴파일된다.
컨텍스트(this)와 프로퍼티 레퍼런스의 경계도 함께 사용하는 형태로 변경
컨텍스트를 활용하기 때문에 getValue와 setValue가 여러 개 있어도 문제가 없다. 상황에 따라서 적절한 메소드가 선택됨
위임 프로퍼티는 확장 함수로도 만들 수 있다.
코틀린 stdlib에서 알아 두면 좋은 프로퍼티 델리게이터
lazy -> 지연 초기화Delegates.observable -> 프로퍼티의 데이터가 변할 때마다 callback을 받을 수 있다.Delegates.vetoable -> observable과 거의 유사하지만 반환 값이 있다Delgates.notNull -> 프로퍼티를 non-null 타입으로 변경