0
votes

I have an Interface that I use as the common data source for my RecyclerView Adapters, which looks like this:

interface GenericRVAdapterDataSource {
    fun getCellCount() : Int
    fun getViewModelForCell(position : Int) : CellViewModel
}

Now, I have two other Interfaces that extend this one:

interface GroupHomeDataSource : GenericRVAdapterDataSource {
    fun getJoinedGroupsCount() : Int
    fun getJoinedGroupViewModel(forIndex : Int) : GroupHomeCellViewModel

    override fun getCellCount(): Int = getJoinedGroupsCount()
    override fun getViewModelForCell(position: Int): CellViewModel = getJoinedGroupViewModel(position)
}

and:

interface GroupSuggestedDataSource : GenericRVAdapterDataSource {
    fun getSuggestedGroupsCellCount() : Int
    fun getSuggestedGroupViewModelForCell(atIndex : Int) : GroupHomeCellViewModel

    override fun getCellCount(): Int = getSuggestedGroupsCellCount()
    override fun getViewModelForCell(position: Int): CellViewModel = getSuggestedGroupViewModelForCell(position)
}

However, when I implement both interfaces into the class:

class GroupHomeViewModel(app : Application) : AndroidViewModel(app), GroupHomeDataSource, GroupSuggestedDataSource, GroupsHomeInteractionLogic {...}

I got the error:

Class 'GroupHomeViewModel' must override public open fun getCellCount(): Int defined in GroupHomeDataSource because it inherits multiple interface methods of it

For now, I've avoided the problem by just storing both interfaces as variables:

val joinedGroupsDataSource = object: GroupHomeDataSource {
    override fun getJoinedGroupsCount(): Int = joinedGroupsList.size
    override fun getJoinedGroupViewModel(forIndex: Int): GroupHomeCellViewModel = joinedGroupsList[forIndex]
}

val suggestedGroupsDataSource = object: GroupSuggestedDataSource {
    override fun getSuggestedGroupsCellCount(): Int = suggestedGroupsList.size
    override fun getSuggestedGroupViewModelForCell(atIndex: Int): GroupHomeCellViewModel = suggestedGroupsList[atIndex]
}

However, I'm not sure that's the most effective way to resolve this diamond problem - if I can even call it that.

Do I just do what the compiler tells me to do and implement getCellCount() and redirect it to one of the interfaces' implementations using:

//MARK:- super interface implementation

override fun getCellCount(): Int {
    return super<GroupHomeDataSource>.getCellCount()
    //Or: return super<GroupSuggestedDataSource>.getCellCount()
}

override fun getViewModelForCell(position: Int): CellViewModel {
    return super<GroupHomeDataSource>.getViewModelForCell(position)
    //Or: return super<GroupSuggestedDataSource>.getViewModelForCell(position)
}

//ENDMARK

Or do I implement that method while determining which of the interfaces calls for it (is there a method for this)?

1

1 Answers

1
votes

The compiler cannot choose between multiple implementations on its own. But, the whole implementation looks a little overwhelmed. Usually you shouldn't create extended DataSource for each case, use a Generic interface instead. If GroupHomeViewModel provides multiple data sources, just create different properties, as you did.

interface CellViewModel
interface GroupHomeCellViewModel : CellViewModel

interface RVAdapterDataSource<T : CellViewModel> {
    fun getCellCount() : Int
    fun getViewModelForCell(position : Int) : T
}

class ListAdapterDataSource<T : CellViewModel>(
  private val list: List<T>
) : RVAdapterDataSource<T> {
    override fun getCellCount() = list.size
    override fun getViewModelForCell(forIndex: Int) = list[forIndex]
}

class GroupHomeViewModel(
    joinedGroupList: List<GroupHomeCellViewModel>,
    suggestedGroupList: List<GroupHomeCellViewModel>
) {
  val joinedGroupsDataSource = ListAdapterDataSource(joinedGroupList)
  val suggestedGroupsDataSource = ListAdapterDataSource(suggestedGroupList)
}