Skip to content

Instantly share code, notes, and snippets.

@AAverin
Last active October 6, 2017 17:35
Show Gist options
  • Save AAverin/c65d2c485be0f4c3ecdaa2ef049aebfe to your computer and use it in GitHub Desktop.
Save AAverin/c65d2c485be0f4c3ecdaa2ef049aebfe to your computer and use it in GitHub Desktop.
A simple consistency manager implementation on Kotlin. You can subscribe on some class changes, and notify subscribers about that class being updated. Convinient when you have data being displayed in many different places and you need it up to date any time it changes, eg. somebody is making item favorite and 'star' icons should update everywhere
interface ConsistencyManagerContract {
fun notifyUpdateModel(model: Any)
fun notifyUpdateClass(kclass: KClass<*>)
fun subscribe(modelClass: KClass<*>, callback: WeakReference<(Any?) -> Unit>)
}
class ConsistencyManager : ConsistencyManagerContract {
private val subscriptionsMap: MutableMap<KClass<*>, MutableList<WeakReference<(Any?) -> Unit>>> = mutableMapOf()
override fun notifyUpdateModel(model: Any) {
val kotlinClass = model.javaClass.kotlin
subscriptionsMap[kotlinClass]?.forEach {
it.get()?.invoke(model)
}
}
override fun notifyUpdateClass(kclass: KClass<*>) {
subscriptionsMap[kclass]?.forEach {
it.get()?.invoke(null)
}
}
override fun subscribe(modelClass: KClass<*>, callback: WeakReference<(Any?) -> Unit>) {
var subscriptionsForModel = subscriptionsMap[modelClass]
if (subscriptionsForModel == null) {
subscriptionsForModel = mutableListOf(callback)
subscriptionsMap.put(modelClass, subscriptionsForModel)
} else {
if (subscriptionsForModel.firstOrNull() { it.get() == callback.get() } == null) {
subscriptionsForModel.add(callback)
}
}
}
}
@RunWith(PowerMockRunner::class)
@PrepareForTest()
class ConsistencyManagerTest {
private val classToTest = ConsistencyManager()
private val model = Article::class
private var testCallback1Called = 0
private var testCallback2Called = 0
private val testCallback1: (Any?) -> Unit = { a ->
testCallback1Called++
}
private val testCallback2: (Any?) -> Unit = { a ->
testCallback2Called++
}
@Test
fun subscribesModel() {
// given
classToTest.subscribe(model, WeakReference(testCallback1))
// when
classToTest.notifyUpdateModel(Article())
// then
assertThat(testCallback1Called, isEqualTo(1))
}
@Test
fun subscribesModelOnlyOnce() {
// given
classToTest.subscribe(model, WeakReference(testCallback1))
classToTest.subscribe(model, WeakReference(testCallback1))
classToTest.subscribe(model, WeakReference(testCallback1))
// when
classToTest.notifyUpdateModel(Article())
// then
assertThat(testCallback1Called, isEqualTo(1))
}
@Test
fun subscribesMultipleCallbacks() {
// given
classToTest.subscribe(model, WeakReference(testCallback1))
classToTest.subscribe(model, WeakReference(testCallback2))
// when
classToTest.notifyUpdateModel(Article())
// then
assertThat(testCallback1Called, isEqualTo(1))
assertThat(testCallback2Called, isEqualTo(1))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment