Kotlin

[Kotlin] Kotlin의 Delegates 알아보기 - observable, vetoable

728x90

 

 

 디자인 패턴에서 Delegate Pattern이란 어떠한 기능을 자기 자신이 처리하지 않고 다른 객체에 일을 위임시켜 그 객체가 일을 처리하게끔 하는 것이다. Kotlin의 Delegates를 활용하면 여러 가지 일을 간단하게 처리할 수가 있다.

 이 글에서는 Delegates의 observable과 vetoable를 활용하는 방법을 알아볼 것이다. observable과 vetoable을 사용하면 어떤 데이터의 값이 변경되었는지 쉽게 알아낼 수가 있다. 다시 말해, 옵저버 패턴을 쉽게 구현할 수가 있다.

 

 

observable

 observable은 위에서 언급한 대로 프로퍼티를 observable 하게 만들어준다. 이것을 이용하면 프로퍼티의 데이터가 변할 때마다 callback을 받을 수 있다.

public inline fun <T> observable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit):
        ReadWriteProperty<Any?, T> =
    object : ObservableProperty<T>(initialValue) {
        override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) = onChange(property, oldValue, newValue)
    }

 Delegates.observable() 코드를 보면 인자로 initialValue와 onChange 함수를 받는 것을 볼 수 있다. initialValue는 이름 그대로 프로퍼티의 초기값을 뜻한다. onChange 함수는 프로퍼티의 값이 변경됐을 때 호출되는 callback 함수이다. onChange 함수에는 Property와 이전 값(oldValue), 새로운 값(newValue)가 전달된다.

 

 

예제를 한번 봐보자.

var observableField: Int by Delegates.observable(0) { property, old, new ->
    println("old: $old, new: $new")
}

fun main() {
    println(observableField) // 0
    
    observableField = 1
    
    println(observableField) // 1
}
0
old: 0, new: 1
1

 observableField라는 이름의 프로퍼티를 선언할 때 Delegates.observable()을 사용해 Observable로 만들어준다. 초기값으로는 0을 주었으며, onChange 함수에는 변경된 값과 이전 값을 프린트하게끔 작성했다.

 main() 함수에서 observableField의 값을 1로 변경시키면 onChange 콜백 함수가 동작하여 안의 동작을 수행하게 된다.

 이렇게 프로퍼티를 Observable로 만드는 것을 Delegates에 위임할 수가 있다.

 

 

vetoable

 vetoable은 observable과 거의 유사하지만 반환 값이 있다는 차이점이 있다.

public inline fun <T> vetoable(initialValue: T, crossinline onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean):
        ReadWriteProperty<Any?, T> =
    object : ObservableProperty<T>(initialValue) {
        override fun beforeChange(property: KProperty<*>, oldValue: T, newValue: T): Boolean = onChange(property, oldValue, newValue)
    }

 observable의 onChange 함수가 Unit을 반환했다면, vetoable의 onChange 함수는 Boolean 값을 반환한다. 결론부터 말하자면, onChange 함수의 반환 값이 true일 때만 프로퍼티의 값을 갱신해준다.

 

var vetoableField: Int by Delegates.vetoable(0) { property, old, new ->
    println("old: $old, new: $new")
    
    new % 2 == 0
}

fun main() {
    println(vetoableField)
    vetoableField = 1
    println(vetoableField)
    vetoableField = 2
    println(vetoableField)
}
0
old: 0, new: 1
0
old: 0, new: 2
2

 observable과 거의 유사하지만 onChange 함수의 반환 조건으로 새로운 값이 짝수일 때만 true를 반환하게끔 설정했다. 따라서 main() 함수에서 값을 홀수로 설정해주면 값이 갱신되지 않고, 짝수로 설정해줬을 때만 갱신되는 것을 볼 수 있다.

 이처럼 Delegates.vetoable()을 활용하면 프로퍼티에 들어가는 값을 보다 쉽게 제한할 수가 있다.

 

참고

codechacha.com/ko/kotlin-delegates-observable/

 

 

728x90