【问题标题】:Kotlin factory interface with generics带有泛型的 Kotlin 工厂接口
【发布时间】:2025-12-06 23:45:01
【问题描述】:

我的 Kotlin 代码中有一个工厂接口,就像这样(使用 Guava 的 TypeToken):

interface ResultMapperFactory {
    fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>?
}

到目前为止,一切都很好。这在调用它时非常容易使用,但是实现几乎总是需要不安全的强制转换:

object StringFactory : ResultMapperFactory {
    override fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>? {
        return if (type.rawType == String::class.java) MyStringMapper as ResultMapper<T> else null
    }
}

这很难看,但我用一个绝妙的技巧克服了它。首先,一个用于创建TypeToken 实例的实用函数:

inline fun <reified T> typeToken(): TypeToken<T> = object : TypeToken<T>() {}

现在我在我的工厂接口中添加了一个伴随对象:

companion object {

    inline operator fun <reified R> invoke(crossinline body: (TypeToken<R>, MapperLookupContext) -> ResultMapper<R>?): ResultMapperFactory {
        val t = typeToken<R>().type
        return object : ResultMapperFactory {
            override fun <T> get(type: TypeToken<T>, context: MapperLookupContext): ResultMapper<T>? {
                return if (type.isSubtypeOf(t)) body(type as TypeToken<R>, context) as ResultMapper<T>? else null
            }
        }
    }
}

这使我可以在一个地方进行未经检查(但安全)的转换,我可以编写如下代码:

val stringMapper: ResultMapper<String> = TODO()
val stringMapperFactory = ResultMapperFactory<String> { type, context ->
    stringMapper
}

但是,一旦我想实现一个接受 TypeToken&lt;List&lt;T&gt;&gt; 并返回 ResultMapper&lt;List&lt;T&gt;&gt; 的工厂,这种方法也会崩溃,因为我没有地方可以放置 T 参数。

我很想听听你的建议。

【问题讨论】:

  • 你的意思是T不是具体类型?
  • 没错。我想写一个工厂,为List&lt;T&gt; 为任何T 创建一个映射器。这是可能的,因为工厂可以查找如何将T 类型的元素映射到MapperLookupContext

标签: generics kotlin factory


【解决方案1】:

我自己找到了解决方案,使用我在原始问题中发布的invoke 操作符 fun 我可以编写以下内容:

private class ListResultMapper<out E>(private val elementMapper: ResultMapper<E>) : ResultMapper<List<E>> { /* ... */ }

val listMapperFactory = ResultMapperFactory<List<*>> { type, context -> context.resultMapperFactory.get(type.elementType(), context)?.let { ListResultMapper(it) } }

【讨论】:

    最近更新 更多