這是一個可重置的懶惰的快速版本,它可以更優雅,需要雙重檢查線程安全性,但這基本上是這個想法。您需要管理(跟蹤)懶惰代理的內容,以便您可以調用重置,然後可以管理和重置。這在這些管理類中包裝lazy()
。
這是你的最後一節課的樣子,作爲一個例子:
class Something {
val lazyMgr = resettableManager()
val prop1: String by resettableLazy(lazyMgr) { ... }
val prop2: String by resettableLazy(lazyMgr) { ... }
val prop3: String by resettableLazy(lazyMgr) { ... }
}
然後讓懶的都回去訪問它們對下一次新的價值觀:
lazyMgr.reset() // prop1, prop2, and prop3 all will do new lazy values on next access
執行可重置的懶惰:
class ResettableLazyManager {
// we synchronize to make sure the timing of a reset() call and new inits do not collide
val managedDelegates = LinkedList<Resettable>()
fun register(managed: Resettable) {
synchronized (managedDelegates) {
managedDelegates.add(managed)
}
}
fun reset() {
synchronized (managedDelegates) {
managedDelegates.forEach { it.reset() }
managedDelegates.clear()
}
}
}
interface Resettable {
fun reset()
}
class ResettableLazy<PROPTYPE>(val manager: ResettableLazyManager, val init:()->PROPTYPE): Resettable {
@Volatile var lazyHolder = makeInitBlock()
operator fun getValue(thisRef: Any?, property: KProperty<*>): PROPTYPE {
return lazyHolder.value
}
override fun reset() {
lazyHolder = makeInitBlock()
}
fun makeInitBlock(): Lazy<PROPTYPE> {
return lazy {
manager.register(this)
init()
}
}
}
fun <PROPTYPE> resettableLazy(manager: ResettableLazyManager, init:()->PROPTYPE): ResettableLazy<PROPTYPE> {
return ResettableLazy(manager, init)
}
fun resettableManager(): ResettableLazyManager = ResettableLazyManager()
而一些單元測試,以確保:
class Tester {
@Test fun testResetableLazy() {
class Something {
var seed = 1
val lazyMgr = resettableManager()
val x: String by resettableLazy(lazyMgr) { "x ${seed}" }
val y: String by resettableLazy(lazyMgr) { "y ${seed}" }
val z: String by resettableLazy(lazyMgr) { "z $x $y"}
}
val s = Something()
val x1 = s.x
val y1 = s.y
val z1 = s.z
assertEquals(x1, s.x)
assertEquals(y1, s.y)
assertEquals(z1, s.z)
s.seed++ // without reset nothing should change
assertTrue(x1 === s.x)
assertTrue(y1 === s.y)
assertTrue(z1 === s.z)
s.lazyMgr.reset()
s.seed++ // because of reset the values should change
val x2 = s.x
val y2 = s.y
val z2 = s.z
assertEquals(x2, s.x)
assertEquals(y2, s.y)
assertEquals(z2, s.z)
assertNotEquals(x1, x2)
assertNotEquals(y1, y2)
assertNotEquals(z1, z2)
s.seed++ // but without reset, nothing should change
assertTrue(x2 === s.x)
assertTrue(y2 === s.y)
assertTrue(z2 === s.z)
}
}
你在尋找一個懶惰的可變變量,你可以隱式地初始化,但也可以顯式設置,或者你正在尋找一個可以重新加載的加載緩存? – mfulton26
我想懶惰地初始化一個屬性,並根據需要重置它。在第一次初始化之前重置狀態 –
您需要一個自定義委託,這是相對容易編寫的。如果你的場景經常被使用,這甚至可以在stdlib – voddan