1

Part of a current project involves converting from types coupled to a database and a generic type used when serializing the results out to clients via Json, the current implementation in Scala uses type inference to correctly perform the transformation, using Scala's TypeTag:

def Transform[A: TypeTag](objects:Seq[A]):Seq[Children] = typeOf[A] match {
  case pc if pc =:= typeOf[ProductCategory] =>
    TransformProductCategory(objects.asInstanceOf[Seq[ProductCategory]])

  case pa if pa =:= typeOf[ProductArea] => 
    TransformProductArea(objects.asInstanceOf[Seq[ProductArea]])

  case pg if pg =:= typeOf[ProductGroup] =>
    TransformProductGroup(objects.asInstanceOf[Seq[ProductGroup]])

  case psg if psg =:= typeOf[ProductSubGroup]  =>
    TransformProductSubGroup(objects.asInstanceOf[Seq[ProductSubGroup]])

  case _ => 
    throw new IllegalArgumentException("Invalid transformation")
}

The types used as input are all case classes and are defined internally within the application, for example:

case class ProductCategory(id: Long, name: String, 
                           thumbnail: Option[String], 
                           image:Option[String], 
                           sequence:Int)

This approach, although suitable at the moment, doesn't feel functional or scalable when potentially more DB types are added. I also feel using asInstanceOf should be redundant as the type has already been asserted. My limited knowledge of implicits suggests they could be used instead to perform the transformation, and remove the need for the above Transform[A: TypeTag](objects:Seq[A]):Seq[Children] method altogether. Or maybe there is a different approach I should have used instead?

4

2 回答 2

1

你可以像这样定义一个特征:

trait Transformer[A] {
  def transformImpl(x: Seq[A]): Seq[Children]
}

然后你可以定义一些实例:

object Transformer {
  implicit val forProduct = new Transformer[ProductCategory] {
     def transformImpl(x: Seq[ProductCategory]) = ...
  }
  ...
}

最后:

def transform[A: Transformer](objects:Seq[A]): Seq[Children] = 
   implicitly[Transformer[A]].transformImpl(objects)

最好,您应该在Transformer对象或与您的类别类对应的对象中定义您的隐式实例。

于 2014-07-01T11:05:21.367 回答
1

我不确定您的程序应该如何工作我也不知道您的任何转换是自制类型还是您从库中提取的东西,但是无论如何我可能有一个解决方案

东西match真的很好用,是case classes

因此,您可以将它们全部包装在案例类(如果您需要随身携带数据)或案例对象(如果您不需要)中,而不是手动检查输入数据的类型

这样你就可以做这样的事情:

// this code assumes ProductCategory, ProductArea, etc. 
// all extends the trait ProductType
def Transform(pType: ProductType): Seq[Children] = pType match {
  case ProductCategory(objects)  => TransformProductCategory(objects)
  case ProductArea(objects)      => TransformProductArea(objects)
  case ProductGroup(objects)     => TransformProductGroup(objects)
  case ProductSubGroup(objects)  => TransformProductSubGroup(objects)
}

通过将所有内容包装在案例类中,您可以准确指定要携带的数据类型,只要它们(案例类,而不是数据)都继承自同一个类/特征,您应该没问题

而且由于只有少数类扩展ProductType您不需要默认情况,因为没有默认情况!

这样做的另一个好处是它可以无限扩展。只需添加更多案例和案例类!

请注意,此解决方案需要您大量重构代码,因此在您投入其中之前请记住这一点。

于 2014-07-01T10:53:15.400 回答