4

我有一个代表销售订单的类:

class SalesOrder(val f01:String, val f02:Int, ..., f50:Date)

字段有fXX多种类型。我面临创建订单审计跟踪的问题。给定该类的两个实例,我必须确定哪些字段已更改。我想出了以下几点:

class SalesOrder(val f01:String, val f02:Int, ..., val f50:Date){

  def auditDifferences(that:SalesOrder): List[String] = {

    def diff[A](fieldName:String, getField: SalesOrder => A) =
      if(getField(this) != getField(that)) Some(fieldName) else None

    val diffList = diff("f01", _.f01) :: diff("f02", _.f02) :: ...
                :: diff("f50", _.f50) :: Nil

    diffList.flatten
  }    
}

我想知道编译器对所有_.fXX函数做了什么:它们是否只实例化一次(静态),并且可以由我的类的所有实例共享,还是每次我创建我的类的实例时都会实例化它们?

我担心的是,由于我将使用大量 SalesOrder 实例,因此可能会产生大量垃圾。我应该使用不同的方法吗?

4

2 回答 2

2

解决此问题的一种干净方法是使用标准库的Ordering类型 class。例如:

class SalesOrder(val f01: String, val f02: Int, val f03: Char) {
  def diff(that: SalesOrder) = SalesOrder.fieldOrderings.collect {
    case (name, ord) if !ord.equiv(this, that) => name
  }
}

object SalesOrder {
  val fieldOrderings: List[(String, Ordering[SalesOrder])] = List(
    "f01" -> Ordering.by(_.f01),
    "f02" -> Ordering.by(_.f02),
    "f03" -> Ordering.by(_.f03)
  )
}

进而:

scala> val orderA = new SalesOrder("a", 1, 'a')
orderA: SalesOrder = SalesOrder@5827384f

scala> val orderB = new SalesOrder("b", 1, 'b')
orderB: SalesOrder = SalesOrder@3bf2e1c7

scala> orderA diff orderB
res0: List[String] = List(f01, f03)

您几乎可以肯定不需要担心原始配方的性能,但由于不相关的原因,这个版本(可以说)更好。

于 2013-06-30T23:35:19.733 回答
1

是的,这创造了 50 个短暂的功能。我认为你不应该担心,除非你有明显的证据表明这会导致你的案例出现性能问题。

但是我会定义一个转换SalesOrder为 a的方法Map[String, Any],然后你就可以

trait SalesOrder {
  def fields: Map[String, Any]
}
def diff(a: SalesOrder, b: SalesOrder): Iterable[String] = {
  val af = a.fields
  val bf = b.fields 
  af.collect { case (key, value) if bf(key) != value => key }
}

如果字段名称确实只是增量数字,您可以简化

trait SalesOrder {
  def fields: Iterable[Any]
}
def diff(a: SalesOrder, b: SalesOrder): Iterable[String] =
  (a.fields zip b.fields).zipWithIndex.collect { 
    case ((av, bv), idx) if av != bv => f"f${idx + 1}%02d"
  }
于 2013-06-30T20:29:36.187 回答