scala中不可变的可组合构建器

时间:2018-05-18 18:26:39

标签: scala

我对如何改进下面的代码感兴趣。我们的想法是构建一个不可变的可组合构建器。最后,构建器只构建Map [String,Object]。我希望能够定义可以重用的核心构建器组件,并且还允许人们定义自己的其他构建器以扩展主构建器。我能够这样做,但不能没有反思的丑陋使用。代码如下:

object TestPizzaBuilder {
  def main(args: Array[String]): Unit = {

    val build = new PizzaBuilder()
      .withCheese("blue")
      .withSauce("tomato")
      .build()

    println(build)
  }
}

object PizzaBuilder {
  type BuilderParams = Map[String, Object]
}

class PizzaBuilder(params: BuilderParams = Map.empty) extends BaseBuilder[PizzaBuilder](params: BuilderParams)
  with CheeseBuilder[PizzaBuilder]
  with SauceBuilder[PizzaBuilder] {
}

abstract class BaseBuilder[A <: BaseBuilder[A]](params: BuilderParams)(implicit tag: ClassTag[A]) {

  protected def _copy(tuples: (String, Object)*): A = {
    val constr = tag.runtimeClass.getConstructors()(0)
    constr.newInstance(params ++ tuples).asInstanceOf[A]
  }

  def build(): Map[String, Object] = {
    params
  }
}

trait CheeseBuilder[A <: BaseBuilder[A]] {
  this: BaseBuilder[A] =>
  def withCheese(cheese: String): A = _copy("cheese" -> cheese)
}

trait SauceBuilder[A <: BaseBuilder[A]] {
  this: BaseBuilder[A] =>
  def withSauce(sauce: String): A = _copy("sauce" -> sauce)
}

您是否有建议如何在此方案中避免反射,同时保持构建器不可变,并允许组建其他小型构建器的构建器。

1 个答案:

答案 0 :(得分:3)

最小的变化是传递构造函数(作为函数)而不是ClassTag

abstract class BaseBuilder[A <: BaseBuilder[A]](params: BuilderParams)(constructor: BuilderParams => A) {

  protected def _copy(tuples: (String, Object)*): A = constructor(params ++ tuples)

  def build(): Map[String, Object] = {
    params
  }
}

// or class PizzaBuilder(params: BuilderParams = Map.empty) extends BaseBuilder[PizzaBuilder](params)(new PizzaBuilder(_))
case class PizzaBuilder(params: BuilderParams = Map.empty) extends BaseBuilder[PizzaBuilder](params)(PizzaBuilder)
  with CheeseBuilder[PizzaBuilder]
  with SauceBuilder[PizzaBuilder] {
}