我在Kotlin中正在努力使用泛型/接口/实现。
问题是为什么我不能像这样将实现传递给HabitsRepository:
class HabitsRepository(habitDao: HabitDao, habitConverter: HabitConverter) :
AbstractRepository<AbstractDataSource<AbstractEntity>, AbstractConverter<AbstractModel, AbstractEntity>>(
habitDao,
habitConverter
)
我收到以下错误
我的设置如下:
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))
}
HabitDao
不是AbstractDataSource<AbstractEntity>
。定义为AbstractDataSource<Habit>
。当泛型类型未定义为in
或out
时,则其为invariant,这意味着您必须传递具有确切类型的参数,而不是超类型或子类型。 HabitConverter
及其两个超类的泛型都有类似的问题。
甚至更进一步,您的HabitDao
是AbstractDataSource
的子类,因此您要在两个层次上打破不变性。
您的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
)
但是AbstractDataSource
和AbstractConverter
都是其通用类型的生产者和使用者,因此它们的类型必须是不变的。