Today I Learned

델리게이션을 통한 확장 (2) 본문

Kotlin/다재다능 코틀린 프로그래밍

델리게이션을 통한 확장 (2)

하이라이터 2023. 9. 8. 14:44
728x90

변수와 속성 델리게이션

변수 델리게이션

package com.agiledeveloper.delegates
import kotlin.reflect.KProperty
class PoliteString(var content : String) {
  operator fun getValue(thisRef: Any?, property: KProperty<*>) =
    content.replace("stupid", "s****")
  operator fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
    content = value
  }
}
import com.agiledeveloper.delegates.PoliteString
var commnet: String by PoliteString("Some nice message")
println(comment)
comment = "This is stupid"
println(comment) //This is s*****
  • PoliteString 클래스는 델리게이션으로만 작동한다.
  • comment 변수를 PoliteString을 사용하도록 변경하면, String이 PoliteString에 접근할 때 델리게이션을 사용한다.

 

속성 델리게이션

  • 지역변수 뿐만 아니라 객체의 속성에도 델리게이션 접근을 사용할 수 있다.
import kotlin.reflect.KProperty
import kotiln.collections.MutableMap
class PoliteString(var dataSource : MutableMap<String, Any>) {
  operator fun getValue(thisRef: Any?, property: KProperty<*>) =
    (dataSource[property.name] as ? String)?.replace("stupid", "s****") ? : ""
  operator fun setValue(thisRef: Any, property: KProperty<*>, value: String) {
    dataSource[Property.name] = value
  }
}
class PostComment(dataSource: MutableMap<String, Any>) {
  val title: String by dataSource
  var likes: Int by dataSource
  val comment: String by PoliteString(dataSource)
  override fun toString() = "Title: $title Likes: $likes comment: $comment"
}
  • MutableMap<String, Any> 타입의 dataSource는 이 클래스의 속성을 위임받아서 처리해주는 델리게이션이다.
  • title은 String 타입의 읽기 전용 속성이고, like는 Inte 타입의 읽기 전용 속성으로 각각 dataSource에 위임된다.
  • 하지만 comment 속성은 PoliteString에 위임되며, PoliteString은 동일한 dataSource에서 데이터가 저장되고 검색된다.
  • comment 속성의 읽기와 쓰기는 각각 PoliteString 델리게이션의 getValue()와 setValue()을 호출한다. 이 위임을 통해서 comment 값을 dataSource에서 읽거나 저장한다.

 

빌트인 스탠다드 델리게이션

조금 게을러도 괜찮다

fun getTemperature(city: String): Double {
  return 30.0
}
val showTemperature = false
val temperature by lazy { getTemperature(city) }
if (showTemperature && temperature > 20) //(nothing here)
  println("Warm")
else
  println("Noting to report") //Noting to report
  • getTemperature()는 웹서비스에 원격 접속을 해야하기 때문에 약간의 시간이 걸리는 가상의 함수이다.
  • lazy 랩퍼 함수를 사용하면 요청 즉시 실행하지 않고 필요한 순간에만 실행하므로 위의 예제에서는 실행되지 않는다.

 

옵저버블 델리게이션

import kotlin.properties.Delegates.observable
var count by observable(0) { property, oldValue, newValue ->
  println("Property: $property old : $oldValue: new: $newValue")
}
println("The value of Count is : $count")
count++
println("The value of Count is : $count")
count--
println("The value of Count is : $count")
  • observable() 함수의 첫 번째 인자는 초기값으로 count는 0으로 초기화되어있다.
  • 두 번째 인자는 이벤트 핸들러로 사용될 람다 표현식이다. 이 표현식은 속성의 세부사항을 프린트해준다.
The value of Count is : 0
Property: var Observe.count: kotlin.Int old : 0: new: 1
The value of Count is : 1
Property: var Observe.count: kotlin.Int old : 1: new: 0
The value of Count is : 0

 

거부권을 연습하자

  • 리턴 타입이 Unit인 observable과 다르게 vetoable 핸들러를 등록하면 Boolean 결과를 리턴받을 수 있다.
import kotlin.properties.Delegates.vetoable
var count by vetoable(0) { _, oldValue, newValue -> newVlaue > oldValue }
println("The value of Count is : $count")
count++
println("The value of Count is : $count")
count--
println("The value of Count is : $count")
  • property 파라미터를 사용하지 않으므로 컴파일러가 사용하지 않는 변수가 있다는 경고를 주는 것을 피하기 위해 _를 사용했다.
  • 새로운 값이 이전 값보다 클 경우 true를 리턴하고 아닐 경우 false를 리턴하므로 count가 증가하는 것만 가능하다.
The value of Count is : 0
The value of Count is : 1
The value of Count is : 1
728x90
Comments