kyucumber
전체 글 보기

이펙티브 코틀린 아이템 21. 일반적인 프로퍼티 패턴은 프로퍼티 위임으로 만들어라

코틀린은 코드 재사용과 관련해 프로퍼티 위임이라는 새로운 기능을 제공한다.

프로퍼티 위임을 사용하면 일반적인 프로퍼티의 행위를 추출해 재사용할 수 있다.

lazy를 이용해 지연 프로퍼티를 사용하면 생성과 동시에 값을 초기화 할 수 있다.

val value by lazy { createValue() } fun createValue(): String = "Test"

프로퍼티 위임을 사용해 observable 패턴도 쉽게 만들 수 있다.

var items: List<Item> by Delegates.observable(listOf()) { _, _, _ -> notifyDataSetChanged() } var key: String? by Delegates.observable(null) { _, old, new -> Log.e("Key changed from $old to $new") }

간단한 프로퍼티 델리게이트를 살펴보자.

// AS-IS 델리게이트 적용 전 var token: String? = null get() { print("token returned value $field") return field } set(value) { print("token changed from $field to $value") field = value } var attempts: Int = 0 get() { print("attempts returned value $field") return field } set(value) { print("attempts changed from $field to $value") field = value }

위 두 token, attempts는 타입은 다르지만 거의 같은 처리를 하며 프로젝트 내에서 자주 반복되어 사용될 만한 패턴이다. 따라서 프로퍼티 위임을 활용해 추출할 수 있다.

// TO-BE 델리게이트 적용 후 var token: String? by LoggingProperty(null) var attempts: Int by LoggingProperty(0) private class LoggingProperty<T>(var value: T) { operator fun getValue( thisRef: Any?, prop: KProperty<*> ): T { print("${prop.name} returned value $value") return value } operator fun setValue( thisRef: Any?, prop: KProperty<*>, newValue: T ) { val name = prop.name print("changed from $value to $newValue") value = newValue } }

프로퍼티 위임이 어떻게 동작하는지 이해하려면 by가 어떻게 컴파일되는지 살펴보자

@JvmField private val 'token$delegate' = LoggingProperty<String?>(null) var token: String? get() = 'token$delegate'.getValue(this, ::token) set(value) { 'token$delegate'.setValue(this, ::token, value) }

멤버 함수 뿐만 아니라 확장 함수로도 만들 수 있다.

val map: Map<String, Any> = mapOf( "name" to "Marcin", "kotlinProgrammer" to true ) val name by map inline operator fun <V, V1 : V> Map<in String, V> .getvalue(thisRef: Any?, property: KProperty<*>): V1 = getOrImplicitDefault(property.name) as V1

코틀린 stdlib의 아래 프로퍼티 델리게이터를 알아 두면 유용하게 활용할 수 있다.

  • lazy
  • Delegates.observable
  • Delegates.vetoable
  • Delegates.notNull

정리

프로퍼티 델리게이트는 프로퍼티와 관련된 다양한 조작을 할 수 있다. 표준 라이브러리의 lazy와 observable이 대표적인 예이다.

Reference

  • 이펙티브 코틀린 - 프로그래밍 인사이트, 마르친 모스칼라 지음, 윤인성 옮김

개인적인 기록을 위해 작성된 글이라 잘못된 내용이 있을 수 있습니다.

오류가 있다면 댓글을 남겨주세요.

Table of contents