实施可重新分配属性委托的最佳方法

时间:2019-03-09 17:50:43

标签: kotlin

我强加了可转让财产委托

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 Property的工作方式类似于惰性,但是在每次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有本地解决方案?

0 个答案:

没有答案