Kotlin中的泛型。如何通过泛型传递Abstract类的实现

问题描述 投票:0回答:1

我在Kotlin中正在努力使用泛型/接口/实现。

问题是为什么我不能像这样将实现传递给HabitsRepository

class HabitsRepository(habitDao: HabitDao, habitConverter: HabitConverter) :
    AbstractRepository<AbstractDataSource<AbstractEntity>, AbstractConverter<AbstractModel, AbstractEntity>>(
        habitDao,
        habitConverter
    )

我收到以下错误

enter image description here

我的设置如下:

HabitsRepository

 class HabitsRepository(habitDao: HabitDao, habitConverter: HabitConverter) :
    AbstractRepository<AbstractDataSource<AbstractEntity>, AbstractConverter<AbstractModel, AbstractEntity>>(
        habitDao as AbstractDataSource<AbstractEntity>,
        habitConverter as AbstractConverter<AbstractModel, AbstractEntity>
    )

HabitDao

@Dao
interface HabitDao : AbstractDataSource<Habit>{

    @Query("SELECT * FROM habit WHERE id=:id ")
    override fun getById(id: String): Single<Habit>

    @Query("SELECT * FROM habit")
    override fun getAll(): Single<List<Habit>>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    override fun insert(entity: AbstractEntity): Completable

    @Delete
    override fun delete(habit: AbstractEntity) : Completable

    @Update
    override fun update(habit: AbstractEntity): Completable
}

HabitConverter

class HabitConverter : AbstractConverter<HabitModel, Habit> {
    override fun toModel(entity: Habit): HabitModel {
        return HabitModel()
    }

    override fun toEntity(model: HabitModel): Habit {
        return Habit()
    }
}

HabitDatabaseSource

class HabitDatabaseSource @VisibleForTesting constructor(private val habitDao: HabitDao) : HabitDao {

    override fun getById(id: String): Single<Habit> = habitDao.getById(id)

    override fun getAll(): Single<List<Habit>> = habitDao.getAll()

    override fun insert(entity: AbstractEntity): Completable = habitDao.insert(entity)

    override fun delete(habit: AbstractEntity): Completable = habitDao.delete(habit)

    override fun update(habit: AbstractEntity): Completable = habitDao.update(habit)
}

AbstractDataSource

interface AbstractDataSource<T : AbstractEntity> {
    fun getById(id: String): Single<T>
    fun getAll(): Single<List<T>>
    fun insert(entity: AbstractEntity): Completable
    fun delete(entity: AbstractEntity): Completable
    fun update(entity: AbstractEntity): Completable
}

AbstractEntity / AbstractModel

abstract class AbstractEntity
abstract class AbstractModel

AbstractConverter

interface AbstractConverter<AM: AbstractModel, AE: AbstractEntity>{
    fun toModel(entity: AE) : AM
    fun toEntity(model: AM): AE
}

AbstractRepository

abstract class AbstractRepository<ADS: AbstractDataSource<AbstractEntity>, AC: AbstractConverter<AbstractModel, AbstractEntity>>(
    private val abstractDataSource: ADS,
    private val abstractConverter: AC
){
    fun getById(id: String): Single<AbstractModel> {
        return abstractDataSource.getById(id).map { abstractConverter.toModel(it) }
    }

    fun getAll(): Single<MutableList<AbstractModel>> =
        abstractDataSource.getAll().flattenAsObservable {it}.map { abstractConverter.toModel(it) }.toList()

    fun insert(model: AbstractModel): Completable = abstractDataSource.insert(abstractConverter.toEntity(model))

    fun delete(model: AbstractModel): Completable = abstractDataSource.delete(abstractConverter.toEntity(model))

    fun update(model: AbstractModel): Completable = abstractDataSource.update(abstractConverter.toEntity(model))
}
generics kotlin syntax architecture
1个回答
0
投票

HabitDao不是AbstractDataSource<AbstractEntity>。定义为AbstractDataSource<Habit>。当泛型类型未定义为inout时,则其为invariant,这意味着您必须传递具有确切类型的参数,而不是超类型或子类型。 HabitConverter及其两个超类的泛型都有类似的问题。

甚至更进一步,您的HabitDaoAbstractDataSource的子类,因此您要在两个层次上打破不变性。

您的HabitRepository必须声明其正在使用的Habit类的确切类型:

class HabitsRepository(habitDao: HabitDao, habitConverter: HabitConverter) :
    AbstractRepository<HabitDao, HabitConverter>(
        habitDao,
        habitConverter
    )

至少对于您的AbstractRepository,泛型仅出现在生产位置中,因此您可以将其类型声明为out,而不会失去任何功能:

abstract class AbstractRepository<out ADS: AbstractDataSource<AbstractEntity>, out AC: AbstractConverter<AbstractModel, AbstractEntity>> ( //...

然后您可能在HabitsRepository定义上就不那么严格了:

class HabitsRepository(habitDao: HabitDao, habitConverter: HabitConverter) :
    AbstractRepository<AbstractDataSource<Habit>, AbstractConverter<HabitModel, Habit>>(
        habitDao,
        habitConverter
    )

但是AbstractDataSourceAbstractConverter都是其通用类型的生产者和使用者,因此它们的类型必须是不变的。

© www.soinside.com 2019 - 2024. All rights reserved.