在Scala中构造/构建JavaBean对象的最简洁方法是什么?

时间:2011-10-31 11:48:29

标签: java oop scala builder setter

假设Product在我无法调整的Java库中,所以要通过调用setter实例化它:

val product = new Product
product.setName("Cute Umbrella")
product.setSku("SXO-2")
product.setQuantity(5)

我希望能够这样做

val product = new Product {
  _.setName("Cute Umbrella")
  _.setSku("SXO-2")
  _.setQuantity(5)
}

或更好:

val product =
  new Product(name -> "Cute Umbrella", sku -> "SXO-2", quantity -> 5)

Scala可以这样吗?

4 个答案:

答案 0 :(得分:6)

您可以导入设置者,因此您无需限定呼叫:

val product = {
  val p = new Product
  import p._

  setName("Cute Umbrella")
  setSku("SXO-2")
  setQuantity(5)

  p
}

如果Product不是最终的,你也可以匿名对它进行子类化并在构造函数中调用setter:

val product = new Product {
  setName("Cute Umbrella")
  setSku("SXO-2")
  setQuantity(5)
}

只要尝试使用属性名称和值的Map进行实例化,就会在使用反射时丢失静态类型检查。像Apache Commons BeanUtils这样的库可以提供帮助,如果你还想沿着这条路走下去。

另一种方法是传递一系列匿名函数来调用每个setter,并编写一个实用程序方法将它们应用到对象

def initializing[A](a: A)(fs: (A => Unit)*) = { fs.foreach(_(a)); a }

initializing(new Product)(
  _.setName("Cute Umbrella"),
  _.setSku("SXO-2"),
  _.setQuantity(5)
)

答案 1 :(得分:6)

您可以将Product对象创建为工厂,并在scala中调用它。像这样:

object Product {
  def apply(name: String, sku: String, quantity: Int) = {
     val newProd = new Product()
     import newProd._
     setName(name)
     setSku(sku)
     setQuantity(quantity)
     newProd
}

然后你可以完全按照自己的意愿使用它(没有新的)。

   val product = Product(name = "Cute Umbrella", sku = "SXO-2", quantity = 5)

(如果以上内容无法编译,请道歉。在工作中无法访问Scala :(

答案 2 :(得分:1)

为了完整起见,如果你需要反过来,从scala类中读取javabean样式的属性,你可以使用@BeanProperty@BooleanBeanProperty注释:

class MyClass(@BeanProperty foo : String, @BooleanBeanProperty bar : Boolean);

然后从java:

MyClass clazz = new MyClass("foo", true);

assert(clazz.getFoo().equals("foo"));
assert(clazz.isBar());

答案 3 :(得分:1)

我会写一个隐式转换来使用Apache Commons BeanUtils

  import org.apache.commons.beanutils.BeanUtils


  implicit def any2WithProperties[T](o: T) = new AnyRef {
    def withProperties(props: Pair[String, Any]*) = {
      for ((key, value) <- props) { BeanUtils.setProperty(o, key, value) }
      o
    }
  }

  test("withProperties") {
    val l = new JLabel().withProperties("background" -> Color.RED, "text" -> "banana")
    l.getBackground should be (Color.RED)
    l.getText should be ("banana")
  }

您在编译时没有得到属性名称或类型检查,但它非常接近您想要的语法,并且在创建例如testdata时通常非常有用。


或者从@ retronym的功能方法中获取提示

  implicit def any2WithInitialisation[T](o: T) = new AnyRef {
    def withInitialisation(fs: (T =>Unit)*) = { 
      fs.foreach(_(o))
      o
    }
  }

  test("withInitialisation") {
    val l = new JLabel().withInitialisation(
      _.setBackground(Color.RED), 
      _.setText("banana")
    )
    l.getBackground should be (Color.RED)
    l.getText should be ("banana")
  }