【问题标题】:How to make a map of generic consumers interfaces with type contravariance parameters?如何使用类型逆变参数制作通用消费者接口的映射?
【发布时间】:2019-10-25 13:46:17
【问题描述】:

我正在尝试在 Android 中为我的应用实施 SOLID 方法。我按照this post 开发了一个通用接口,在Adapter 类中实现来选择用户的Auth Provider。在我的构造函数中,我需要一个映射,其中包含多个身份验证提供程序(Facebook、Google 等)的可能实现,但是当我构建映射时,编译器会抱怨对象的“不兼容类型”。

我尝试在通用接口中引入一些协变和逆变运算符,并使用“星形投影”映射到地图,但是在构建地图或在我的实现中调用接口的函数时编译器失败。

这是将参数对象扩展到实现的接口

interface IQuery<TResult>

这是一个参数对象的例子

data class FacebookLoginEvent (
        val requestCode: Int,
        val resultCode: Int,
        val data: Intent?
): IQuery<String>

这是 Auth 服务实现的接口

interface IQueryService<TQuery: IQuery<TResult>, TResult> {
    fun execute(query: TQuery): TResult
}

Auth Provider 实现示例

class FacebookSignInFlow(): IQueryService<FacebookLoginEvent, String> {
    override fun execute(query: FacebookLoginEvent): String {
        // Do something with the event
    }
}

使用枚举器选择进行身份验证的提供者的复合类

class CredentialSignInFlow(
        private val signInFlowProviders: Map<
                CredentialSignInFlowProvider,
                IQueryService<IQuery<String>, String>
        >
) {
    fun signIn(provider: CredentialSignInFlowProvider, query: IQuery<String>){
        signInFlowProviders.getValue(provider).execute(query)
    }
}

enum class CredentialSignInFlowProvider{
    FacebookProvider,
    GoogleSilentProvider,
    GoogleProvider
}

当我发送地图时,编译器会这样说

Type inference failed. Expected type mismatch: inferred type is Map<CredentialSignInFlowProvider, FacebookSignInFlow> but Map<CredentialSignInFlowProvider, IQueryService<IQuery<String>, String>> was expected

这是组成对象图的代码

CredentialSignInFlow(mapOf(
    CredentialSignInFlowProvider.FacebookProvider to FacebookSignInFlow()
))

【问题讨论】:

    标签: android generics kotlin


    【解决方案1】:

    问题在于您的 CredentialSignInFlow 完全期望 Map&lt;CredentialSignInFlowProvider, IQueryService&lt;IQuery&lt;String&gt;, String&gt;&gt; 类,并且没有将任何 IQuery&lt;String&gt; 继承者应用到服务泛型中。

    我在这里只能看到一种解决方案 - 也将 CredentialSignInFlow 设为通用。

    class CredentialSignInFlow<T : IQuery<String>>(
            private val signInFlowProviders: Map<
                    CredentialSignInFlowProvider,
                    IQueryService<T, String>
                    >
    ) {
        fun signIn(provider: CredentialSignInFlowProvider, query: T){
            signInFlowProviders.getValue(provider).execute(query)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-09-24
      • 1970-01-01
      • 2021-08-07
      • 2023-02-21
      • 2018-11-28
      • 2023-02-01
      • 2017-01-04
      • 1970-01-01
      相关资源
      最近更新 更多