【发布时间】:2018-10-24 14:27:12
【问题描述】:
我很难理解和/或让 Kotlin 泛型和多态性为我工作。考虑这段代码:
class Item<T: BaseAttributes> {
var id: Long = -1L
lateinit var type: String
lateinit var attributes: T
}
open class BaseAttributes {
lateinit var createdAt: String
lateinit var updatedAt: String
}
open class BaseResponseList<T : BaseAttributes> {
lateinit var items: List<Item<T>> // the collection of items fetched from an API
}
class FruitAttributes(val id: Long, val color: String /* ... */) : BaseAttributes()
class FruitResponseList: BaseResponseList<FruitAttributes>()
// base service for all types of items
interface ApiService {
fun getItems(): BaseResponseList<BaseAttributes>
// fun getItemById(itemId: Long): BaseResponse<BaseAttributes>
/* other CRUD functions here ... */
}
// service for fruits
interface FruitService: ApiService {
override fun getItems(): FruitResponseList // get fruit items
}
我被这个编译器错误难住了,它暗示 FruitResponseList 不是参数化基类 (BaseResponseList<FruitAttributes>) 的子类型:
Return type of 'getItems' is not a subtype of the return type of the overridden member 'public abstract fun getItems(): BaseResponseList<BaseAttributes> defined in ApiService'
我尝试在 BaseAttributes 中使用声明点协方差来告诉编译器我的意图,即 FruitResponseList 是基本响应列表的子类,如下所示:
open class BaseResponseList<out T : BaseAttributes> {
lateinit var items: List<Item<T>> // the collection of items fetched from an API
}
导致此错误:
Type parameter T is declared as 'out' but occurs in 'invariant' position in type List<Item<T>>
如何实现 Fruit 和 Base 响应列表之间的类型-子类型关系?
背景
我正在实现网络代码以针对基于JSON API spec 格式的 API 执行 CRUD 操作,因此我创建了属性和数据 (Item) 类来表示 json 响应对象。
我的目标是减少重复代码的数量,这样我只需为我的应用程序中的每个实体(水果、供应商、买家等)编写一次 API 服务声明。我还想避免为我的应用程序中的每个实体(在干净架构的上下文中)编写数据存储库层的重复/样板实现。我应该能够只指定特定于业务实体的类型(模型/实体),并让一个通用实现来完成获取网络数据的工作。
我认为使用泛型和继承来实现这一点是有意义的。在这个特定示例中,想法是特定于水果的 GET 将返回一个水果响应列表,它是基本响应列表的子类型。非常感谢任何有关此问题的指导或解决此问题的替代方法
【问题讨论】:
标签: android generics kotlin polymorphism retrofit