The Class Delegate Alternative
By using a class delegate, we get the best of both worlds: the FavoriteStore
remains internal to the ItemViewModel
implementation, yet we get a zero-cost implementation of the FavoriteStore
API:
interface FavoriteStore<T> {
fun isFavorite(thingy: T): Boolean
fun toggleFavorite(thingy: T, isFavorite: Boolean)
}
class InMemoryFavoriteStore<T> : FavoriteStore<T> {
private val favorites: MutableMap<T, Boolean> = mutableMapOf()
override fun isFavorite(thingy: T) = favorites[thingy] ?: false
override fun toggleFavorite(thingy: T, isFavorite: Boolean) {
favorites[thingy] = isFavorite
}
}
data class Item(val id: String, val name: String)
class ItemViewModel(favorites: FavoriteStore<Item>) : FavoriteStore<Item> by favorites
fun main() {
val vm = ItemViewModel(InMemoryFavoriteStore())
val item = Item("this is my id", "this is my name")
println("item isFavorite: ${vm.isFavorite(item)}")
vm.toggleFavorite(item, true)
println("item isFavorite: ${vm.isFavorite(item)}")
}
When we try using the FavoriteStore
API on ItemViewModel
, Kotlin forwards those calls along to favorites
, without us having to do that delegation manually. Yet, favorites
is just a constructor parameter — it is not even a property.
Now, in this case, we could also have ItemViewModel
inherit from InMemoryFavoriteStore()
and get the same result. However, in a real-world app, we will want to supply different FavoriteStore
implementations, perhaps through dependency inversion frameworks. Forcing ItemViewModel
to inherit from InMemoryFavoriteStore
would eliminate the flexibility to swap in a different implementation for different circumstances.
Prev Table of Contents Next
This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.