kotlin delegated properties
개요
class Example {
var p: String by Delegate()
}
kotlin을 활용하다 보면 by 키워드등이 활용되는 예시를 만난 적들이 있으며 해당 문법을 잘 모르는 상황에서 당황스러운 경험들이 있습니다.
kotlin delegated property에 대해 이해하기 위해 글을 작성해보가 합니다.
Delegated Properties란?
delegated는 "위임된" 이라는 뜻을 가집니다.
즉 프로퍼티의 속성을 미리 정의된 다른 속성에게 위임한다는 의미를 가집니다.
Kotlin에서는 by 키워드를 활용하여 프로퍼티의 위임을 수행할 수 있습니다.
Interface의 구현체를 다른 객체에게 위임할 수 있고, Property의 Accessor 구현을 다른 객체의 위임할 수도 있습니다.
Accessor는 접근자를 뜻하며 Setter, Getter를 뜻합니다.
Why Delegated Properties
한번 구현하여 라이브러리 추가한 후 나중에 재사용한 것이 유용합니다.
예를 들면 lazy properties, observable properties 등이 존재하고 사용자가 직접 XX properties를 정의해서 재사용할 수 있습니다.
Delegated를 한다는 것은 어떤 의미인가?
다른 객체에서 구현된 getValue, setValue (getter, setter)를 활용한다는 이야기입니다.
다만 불변객체 val이라면 setter를 구현해 줄 필요는 없습니다.
직접 Delegated Property 만들어보기
private class LoggingProperty<T>(var value: T){
operator fun getValue(
thisRef: Any?,
prop: KProperty<*>,
): T{
println("property [${prop.name}]의 조회가 감지되었습니다. 조회된 값[$value]")
return value
}
operator fun setValue(
thisRef: Any?,
prop: KProperty<*>,
newValue: T,
) {
val name = prop.name
println("property [$name]의 변경이 감지되었습니다. 기존값[$value] 변경값[$newValue]")
value = newValue
}
}
여러 변수를 받아야 하므로 제네릭으로 value를 선언해 주고 getValue, setValue에 해당하는 operator를 선언해 줍니다.
해당 Delegated Property는 로깅을 지원하는 프로퍼티로써 get, set이 일어날 때 변경을 감지하여 해당 값을 출력해 줍니다.
thisRef는 프로퍼티가 속한 클래스에 대한 참조입니다.
KProperty는 위임되는 속성에 대한 reflection입니다.
prop.name을 통해서 property의 이름을 가져올 수 있습니다.
테스트를 통해 알아보기
@Test
fun `Delegated Property를 직접 만들어보자`(){
var token: String? by LoggingProperty(null)
token = "hi"
println("어떤 일이 벌어질까요?")
val getToken = token
}
//출력
property [token]의 변경이 감지되었습니다. 기존값[null] 변경값[hi]
어떤 일이 벌어질까요?
property [token]의 조회가 감지되었습니다. 조회된 값[hi]
참고자료
https://junuuu.tistory.com/637
https://kotlinlang.org/docs/delegated-properties.html
https://www.baeldung.com/kotlin/delegated-properties
https://thdev.tech/kotlin/2020/11/27/kotlin_delegation/