复制相同名称属性的简单代码?

时间:2018-03-01 04:30:47

标签: java spring kotlin

我有一个旧的问题长期存在于我的脑海中。当我在Spring中编写代码时,DTO,域对象有很多脏无用的代码。对于语言水平,我在Java中无望,并在Kotlin中看到了一些亮点。这是我的问题:

样式1 我们通常编写以下代码(Java,C ++,C#,...)

    // annot: AdminPresentation 
    val override = FieldMetadataOverride()
    override.broadleafEnumeration = annot.broadleafEnumeration
    override.hideEnumerationIfEmpty = annot.hideEnumerationIfEmpty
    override.fieldComponentRenderer = annot.fieldComponentRenderer

Sytle 2 在Kotlin中使用T.apply()可以简化以前的代码

    override.apply {
        broadleafEnumeration = annot.broadleafEnumeration
        hideEnumerationIfEmpty = annot.hideEnumerationIfEmpty
        fieldComponentRenderer = annot.fieldComponentRenderer
    }

Sytle 3 这样的代码甚至可以简化为这样的代码吗?

    override.copySameNamePropertiesFrom (annot) { // provide property list here
        broadleafEnumeration
        hideEnumerationIfEmpty
        fieldComponentRenderer
    }

第一优先级要求

  1. 仅提供一次property name个列表
  2. property name作为普通代码提供,以便我们可以获得IDE自动完成功能。
  3. 第二优先级要求

    1. 它更倾向于避免样式3的运行时成本。(例如,'反射'可能是一种可能的实现方式,但确实会带来成本。)
    2. 它更喜欢直接生成类似style1 / style2的代码。
    3. 不关心

      1. Style 3的最终语法。
      2. 我是Kotlin语言的新手。是否可以使用Kotlin来定义类似于' Style 3' ?

1 个答案:

答案 0 :(得分:4)

编写一个5行帮助程序来执行此操作应该非常简单,甚至支持复制每个匹配的属性或只选择属性。

虽然如果你正在编写Kotlin代码并大量使用数据类和val(不可变属性),它可能没用。看看:

fun <T : Any, R : Any> T.copyPropsFrom(fromObject: R, vararg props: KProperty<*>) {
  // only consider mutable properties
  val mutableProps = this::class.memberProperties.filterIsInstance<KMutableProperty<*>>()
  // if source list is provided use that otherwise use all available properties
  val sourceProps = if (props.isEmpty()) fromObject::class.memberProperties else props.toList()
  // copy all matching
  mutableProps.forEach { targetProp ->
    sourceProps.find {
      // make sure properties have same name and compatible types 
      it.name == targetProp.name && targetProp.returnType.isSupertypeOf(it.returnType) 
    }?.let { matchingProp ->
      targetProp.setter.call(this, matchingProp.getter.call(fromObject))
    }
  }
}

这种方法使用反射,但它使用非常轻量级的Kotlin反射。我没有计时,但它应该以与手动复制属性几乎相同的速度运行。

现在给出2个课程:

data class DataOne(val propA: String, val propB: String)
data class DataTwo(var propA: String = "", var propB: String = "")

您可以执行以下操作:

  var data2 = DataTwo()
  var data1 = DataOne("a", "b")
  println("Before")
  println(data1)
  println(data2)
  // this copies all matching properties
  data2.copyPropsFrom(data1)
  println("After")
  println(data1)
  println(data2)
  data2 = DataTwo()
  data1 = DataOne("a", "b")
  println("Before")
  println(data1)
  println(data2)
  // this copies only matching properties from the provided list 
  // with complete refactoring and completion support
  data2.copyPropsFrom(data1, DataOne::propA)
  println("After")
  println(data1)
  println(data2)

输出将是:

Before
DataOne(propA=a, propB=b)
DataTwo(propA=, propB=)
After
DataOne(propA=a, propB=b)
DataTwo(propA=a, propB=b)
Before
DataOne(propA=a, propB=b)
DataTwo(propA=, propB=)
After
DataOne(propA=a, propB=b)
DataTwo(propA=a, propB=)