使用泛型的对象转换

Object conversion using generics

我确实有一个对象转换任务让我感到困惑 ;) 假设我有三种(或更多)格式的业务对象

class MapA { /*some implementation */ }

class MapB { /*some implementation */ }

class MapC { /*some implementation */ }

此外,我还有一个 "super object" 存储在数据库中,其中包含 MapA、MapB 和 MapC 的所有属性的超集。

class SuperMap { /* all implemented properties from all maps */ }

我现在需要能够与任何地图类型相互转换。所以我的想法是指定一个特定的Converter接口,将特定的地图转换为超级地图。

interface Converter<F>{

    fun convertFrom(map: F): SuperMap
    fun convertTo(map: SuperMap): F

}

这几种地图类型的所有者只需实现地图类型<->超级地图

class MapAConverter: Converter<MapA> {

    override fun convertFrom(map: MapA): SuperMap {
        return SuperMap()
    }

    override fun convertTo(map: SuperMap): MapA {
        return MapA()
    }
}

/* more converters */

最后,我想到了一个服务,然后执行以下操作: 如果用户想把MapA转换成MapC,服务内部会转换MapA -> SuperMap -> MapC, ... 这样我就不必编写出所有可能的组合...

class ConverterService
{
    private val converters = mutableMapOf<KType, Converter<T>>()

    fun <T>register(converter: Converter<T>){
        this.converters[T::class] = converter
    }

    fun <F, T>Convert(map: F): T{

        // F ... from map
        val conv1 = converters[F::class]
        if (conv1 == null)
            throw Exception("No converter for this type of map")

        // convert to super class
        val sc = conv1.convertFrom(map)

        // T ... to map
        val conv2 = converters[T::class]
        if(conv2 == null){
            throw Exception("No converter for this type of map")
        }

        // convert to desirect class
        return conv2.convertFrom(sc) as T
    }
}

但这不起作用...

  1. converters hashmap 不知道 T

  2. val conv1 = converters[[=​​45=]] 告诉我 F::class 需要 reifeid 并希望将 Convert 转换为内联函数。如果我这样做,它会变得更加复杂......

我的实现思路是这样的:

fun main() {

    // register some converters
    var cs = ConverterService()
    cs.register(MapAConverter())
    cs.register(MapBConverter())
    cs.register(MapCConverter())

    // input is map a
    val ma = MapA()

    // i want map c
    val mc = cs.Convert<MapA, MapC>(ma)

}

能以某种方式实现吗?我很高兴收到任何提示/建议。

谢谢!

  1. 使用mutableMapOf<KClass<*>, Converter<*>>()(意思是Converter with some unknown type parameter)。

  2. 如错误信息所述,您需要 FTreified 才能使用 F::class:

    inline fun <reified F, reified T> Convert(map: F): T { ... }
    

    您在 register 中也需要它。我不确定你为什么认为它 "even more complicated".

  3. 您需要在 Convert 内部进行一些细微的更改:将转换器强制转换为具有正确的类型参数而不是 *,并在末尾使用 convertTo。我会做一个辅助函数

    private inline fun <reified T> converter(): Converter<T> {
        val result = converters[T::class]
        if (result == null) 
            throw Exception("No converter for ${T::class.qualifiedName}")
        else
            return result as Converter<T>
    }
    
    inline fun <reified F, reified T> Convert(map: F): T {
        // F ... from map
        val conv1 = converter<F>()
        // convert to super class
        val sc = conv1.convertFrom(map)
    
        // T ... to map
        val conv2 = converter<T>()
        // convert to desired class
        return conv2.convertTo(sc)
    }