I have these two classes:
class InfoDayViewModel(
day: Day,
application: Application
) : DayViewModel(day, application) {
val dayDeleted = MutableLiveData<Boolean>().apply { value = false }
fun deleteDay() {
viewModelScope.launch {
repository.deleteDay(day)
dayDeleted.value = true
}
}
}
class InfoIdeaViewModel(
idea: Idea,
topic: Topic,
application: Application
) : IdeaViewModel(idea, topic, application) {
val ideaDeleted = MutableLiveData<Boolean>().apply { value = false }
fun deleteIdea() {
viewModelScope.launch {
repository.deleteIdea(idea)
ideaDeleted.value = true
}
}
}
They are very similar but I can't use a superclass because they already have superclasses. So I can create an interface like this one:
interface InfoItemViewModel {
val itemDeleted: MutableLiveData<Boolean>
fun deleteItem()
}
However, I will have to implement the functionality of the interfaces in both classes and I will have to repeat the code. So I can use composition and create a class that contains the implementation of the interface:
abstract class InfoItemViewModelImpl(private val coroutineScope: CoroutineScope) : InfoItemViewModel {
override val itemDeleted = MutableLiveData<Boolean>().apply { value = false }
override fun deleteItem() {
coroutineScope.launch {
deleteItemFromDatabase()
itemDeleted.value = true
}
}
abstract suspend fun deleteItemFromDatabase()
}
And I can make both classes implement this functionality like that:
class InfoIdeaViewModel(
idea: Idea, topic: Topic, application: Application
) : IdeaViewModel(idea, topic, application), InfoItemViewModel {
private val infoItemViewModel = object : InfoItemViewModelImpl(viewModelScope) {
override suspend fun deleteItemFromDatabase() { repository.deleteIdea(idea) }
}
override val itemDeleted get() = infoItemViewModel.itemDeleted
override fun deleteItem() { infoItemViewModel.deleteItem() }
}
class InfoDayViewModel(
day: Day, application: Application
) : DayViewModel(day, application), InfoItemViewModel {
private val infoItemViewModel = object : InfoItemViewModelImpl(viewModelScope) {
override suspend fun deleteItemFromDatabase() { repository.deleteDay(day) }
}
override val itemDeleted get() = infoItemViewModel.itemDeleted
override fun deleteItem() { infoItemViewModel.deleteItem() }
}
However, there is a lot of boilerplate code because in every class I have to create an object that contains the implementation and for every property and function make it use the object.
To solve this I thought about delegation like this:
class InfoDayViewModel(
day: Day, application: Application
) : DayViewModel(day, application), InfoItemViewModel by object : InfoItemViewModelImpl(viewModelScope) {
override suspend fun deleteItemFromDatabase() {
repository.deleteDay(day)
}
}
But that doesn't work. It doesn't recognize viewModelScope and it doesn't recognize repository. InfoItemViewModelImpl
is created before InfoDayViewModel and that's the reason why it can't access these properties. How can I solve it?
Here's one possible workaround. It's less verbose than your solution if you're using this delegate in multiple classes. But it's not very elegant, since the age
becomes a public read-write property.
interface CanRun {
fun run(): String
var age: Int
}
class CanRunImpl : CanRun {
override var age by Delegates.notNull<Int>()
override fun run(): String {
return if (age > 10) "fast" else "slow"
}
}
class Lion : CanRun by CanRunImpl() {
init { age = 5 }
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.