我一直在使用Scala替换Java枚举模式

时间:2014-01-11 23:09:42

标签: scala

在Java中,我做了很多数据集成工作。一直出现的一件事是在多个系统之间映射数据。所以我经常做这样的事情

public enum DataField{
  Field1("xmlField", "dbField", "system1Field";
  private String xml;
  private String db;
  private String sys;

  private DataField(String xml, String db, String sys){
    this.xml = xml;
    this.db = db;
    this.sys = sys;
  }

  public getXml(){
    return this.xml;
  }

  public static DataField valueOfXml(String xml){
    for (DataField d : this.values()){
      if (d.xml.equals(xml)){ return d;}
    }
  }
  bla, bla bla
}

这允许我做的是将字段名称DataField放在我的所有消息中,并能够映射在多个系统中调用该字段的内容。所以在我的XML中,它可能是firstname,在我的数据库中,它可能被称为first_name,但在我的外部接口系统中,它可能被称为first。这种模式非常好地将所有这些结合在一起,并且以紧凑,类型安全的方式使这些类型的系统中的消息传递非常容易。

现在我不记得为什么Scala改变了枚举实现,但我记得当我读它时它是有意义的。但问题是,我将在Scala中使用什么来取代这种设计模式?我讨厌失去它,因为它对我在某一天写的很多系统都非常有用和基础。

感谢

2 个答案:

答案 0 :(得分:5)

我设法为你的案件补充了这种替代品:

sealed class DataField(val xml: String, val db: String, val sys: String)

object DataField {
  case object Field1 extends DataField("xmlField1", "dbField1", "system1Field")
  case object Field2 extends DataField("xmlField2", "dbField2", "system2Field")
  case object Field3 extends DataField("xmlField3", "dbField3", "system3Field")

  val values = List(Field1, Field2, Field3)

  def valueOfXml(xml: String) =
    values.find(_.xml == xml).get
}

令人讨厌的是我们必须手动创建values列表。但是,在这种情况下,我们可以做一些宏黑客攻击来减少样板:

import scala.language.experimental.macros
import scala.reflect.macros.Context

object Macros {
  def caseObjectsFor[T]: List[T] = macro caseObjectsFor_impl[T]

  def caseObjectsFor_impl[T: c.WeakTypeTag](c: Context): c.Expr[List[T]] = {
    import c.universe._

    val baseClassSymbol = weakTypeOf[T].typeSymbol.asClass
    val caseObjectSymbols = baseClassSymbol.knownDirectSubclasses.toList.collect {
      case s if s.isModuleClass && s.asClass.isCaseClass => s.asClass.module
    }

    val listObjectSym = typeOf[List.type].termSymbol
    c.Expr[List[T]](Apply(Ident(listObjectSym), caseObjectSymbols.map(s => Ident(s))))
  }
}

然后我们可以这样做:

val values = Macros.caseObjectsFor[DataField]

而不是手动列出所有案例对象。

为此,必须将基类声明为sealed

答案 1 :(得分:2)

你可以随时做我做的事情,并继续用Java编写枚举。

在我的源代码树中的62个.java文件中,61个是枚举,另一个是package-info.java。