我实施了 Reassignable Property Delegate
internal object UNINITIALIZED_VALUE
class SynchronizedReassignableImpl<out T>(private val initializer: () -> T,
private val expiredPredicate: (T) -> Boolean,
lock: Any? = null) : Reassignable<T> {
@Volatile
private var _value: Any? = UNINITIALIZED_VALUE
private val lock = lock ?: this
override val value: T
get() {
if (!isExpired()) {
@Suppress("UNCHECKED_CAST") (_value as T)
}
return synchronized(lock) {
val _v2 = _value
@Suppress("UNCHECKED_CAST")
if (_v2 !== UNINITIALIZED_VALUE && !expiredPredicate.invoke(_value as T)) {
_v2 as T
} else {
val typedValue = initializer()
_value = typedValue
typedValue
}
}
}
@Suppress("UNCHECKED_CAST")
override fun isExpired(): Boolean = !isInitialized() || expiredPredicate.invoke(_value as T)
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Reassignable value not initialized yet."
operator fun getValue(any: Any, property: KProperty<*>): T = value
operator fun getValue(any: Nothing?, property: KProperty<*>): T = value
}
fun <T> reassignable(initializer: () -> T, expiredPredicate: (T) -> Boolean, lock: Any? = null): SynchronizedReassignableImpl<T> {
return SynchronizedReassignableImpl(initializer, expiredPredicate, lock)
}
interface Reassignable<out T> {
val value: T
fun isInitialized(): Boolean
fun isExpired(): Boolean
}
这段代码声明了 Delegate 属性像惰性一样工作,但在每次 getter 调用时,都会调用谓词来定义值状态(是否过期)。如果该值过期,则将重新分配该值。
例如,它正在工作
class SynchronizedReassignableImplTests {
@Test
fun isReassignable() {
val initializer = { mutableListOf<String>() }
val expiredPredicate = { l: List<String> -> l.size == 2 }
val list by reassignable(initializer, expiredPredicate)
Assertions.assertEquals(0, list.size)
list.add("item ${list.size}")
Assertions.assertEquals(1, list.size)
list.add("item ${list.size}") // list size is 2 on next getter's call it will be reassigned
Assertions.assertEquals(0, list.size)
list.add("item ${list.size}")
Assertions.assertEquals(1, list.size)
}
}
但我只使用 Kotlin 两天,并认为我的解决方案不是那么漂亮。有人可以给我建议吗?或者也许 Kotlin 有一个原生的解决方案?