【问题标题】:Kotlin InheritanceKotlin 继承
【发布时间】:2026-01-12 05:25:01
【问题描述】:

我目前正在学习将我凌乱的代码拆分为 DDD(注意,学习)范式。实体(IEntityIUser)是域层由接口组成,然后在数据层(BaseEntityUser)实现。通过存储库模式访问数据。但正如我为IUserRepository 定义的返回IUser,在数据层我必须手动将它User 转换回IUser 以匹配返回签名。

如何避免强制转换?谢谢。

域层

interface IEntity
{
    var id: Long?
    var name: String?
}

interface IUser : IEntity
{
}

interface IBaseRepository<T: IUser>
{
    fun get(id: Long): Observable<T?>
}

interface IUserRepository : IBaseRepository<IUser>
{
}

数据层

abstract class BaseEntity() : IEntity
{
    @SerializedName("id")
    override var id: Long? = null

    @SerializedName("full_name")
    override var name: String? = null
}

class User() : BaseEntity(), IUser
{
}

interface UserRetrofitApi
{
    @GET("user/{uuid}/")
    fun get(id: Long): Observable<User?>
}

class UserRepository(private val _api: UserRetrofitApi) : IUserRepository
{
    override fun get(id: Long): Observable<IUser?> {
        return _api.get(id) as Observable<IUser?> // How to avoid casting here without resorting to generic UserRepository<T: IUser>
    }
}

【问题讨论】:

  • UserRetrofitApi::get 有什么特殊限制吗?如果没有,只需将其更改为fun get(id: Long): Observable&lt;IUser?&gt;
  • @glee8e,请参阅下面的回复。

标签: generics inheritance kotlin


【解决方案1】:

在基础存储库中声明您的get 函数,如下所示:

fun get(id: Long): Observable<out T?>

同样将UserRepository中的get函数更改为:

override fun get(id: Long): Observable<out IUser?> {
    return _api.get(id)
}

更多信息请参见the docs on variance

【讨论】:

  • 我已通读该文档,与第一次阅读相比,它更有意义。我已经尝试过了,它可以工作。一个后续问题是存储库需要支持 CRUD 操作,我不能声明 UserRepository 是协变的。我已经阅读了 use-site variancetype projections 但我无法解决我自己的问题,因为我传递的是单个对象而不是集合/数组根据给出的示例对象。
【解决方案2】:

如果我理解正确,您只需将UserRetroFitApi.get 的结果更改为Observable&lt;IUser?&gt;

class UserRetrofitApi
{
    fun get(id: Long): Observable<IUser?> {
        val user = User()
        user.id = 1
        user.name = "User 1"
        return Observable.just(user)
    }
}

【讨论】:

  • 我正在使用Retrofit 与服务器api进行交互。据我了解,Retrofit 对象需要是一个具有默认构造函数的类,它将有助于执行来自和到 json 对象的序列化和序列化。我更新了示例代码以反映实际的 Retrofit 界面。