用于Scala和Java的类型安全的Builder库

时间:2011-06-14 16:48:16

标签: java scala scala-java-interop

以下是Scala中类型安全,流畅的构建器模式,如http://www.tikalk.com/java/blog/type-safe-builder-scala-using-type-constraints所述。它与Builder Library for Scala and Java类似,但专门处理编译时构建器检查。这怎么能从Java调用?在给出“scala.Predef $$ eq $ colon $ eq”参数的情况下,是否可以使用干净的Scala AND Java API?

sealed trait TBoolean
sealed trait TTrue extends TBoolean
sealed trait TFalse extends TBoolean

class Builder[HasProperty <: TBoolean] private(i: Int) {
  protected def this() = this(-1)
  def withProperty(i: Int)(implicit ev: HasProperty =:= TFalse) = new Builder[TTrue](i)
  def build(implicit ev: HasProperty =:= TTrue) = println(i)
}

//javap output
    public class Builder extends java.lang.Object implements scala.ScalaObject{
    public Builder withProperty(int, scala.Predef$$eq$colon$eq); //How is this called from Java?
    public void build(scala.Predef$$eq$colon$eq);
    public Builder();
}
object Builder {
  def apply() = new Builder[TFalse]
}

2 个答案:

答案 0 :(得分:6)

您应该能够使用Java中的这个API,与Scala版本相比会产生一些额外的噪音。一些便利领域会让事情变得安静:

object Builder {
   def apply() = new Builder[TFalse]
   val unassigned = =:=.tpEquals[TFalse]
   val assigned = =:=.tpEquals[TTrue] 
}

Java客户端代码应该看起来像

Builder$.MODULE$.apply()
   .withProperty(10, Builder$.MODULE$.unassigned())
   .build(Builder$.MODULE$.assigned());

build方法必须检查是否已分配每个属性,因此在推广到多个属性时会产生相当大的噪音:

Builder$.MODULE$.apply()
   .withProp1(10, Builder$.MODULE$.unassigned())
   .withProp2(20, Builder$.MODULE$.unassigned())
   .withProp3(30, Builder$.MODULE$.unassigned())
   // ...
   .build(Builder$.MODULE$.assigned(), 
          Builder$.MODULE$.assigned(), 
          Builder$.MODULE$.assigned(), 
          //...
         );

在帮助程序类(以及一些静态导入)中有一些静态委托,你应该可以将其归结为:

createBuilder()
   .withProp1(10, unassigned())
   .withProp2(20, unassigned())
   .build(assigned(), assigned());

答案 1 :(得分:3)

好的,感谢Aaron和ittayd ......这是一个为Scala和Java提供流畅API的构建器:

import annotation.bridge

sealed trait TBoolean
sealed trait TTrue extends TBoolean
sealed trait TFalse extends TBoolean

class Builder[HasProperty <: TBoolean] private(i: Int) {
  protected def this() = this(-1)

  def withProperty(i: Int)(implicit ev: HasProperty =:= TFalse) = new Builder[TTrue](i)
  def build(implicit ev: HasProperty =:= TTrue):Int = i
  @bridge def withProperty(i: Int) = new Builder[TTrue](i)
  @bridge def build = build(null)
}

object Builder {
  def apply() = new Builder[TFalse]
  val unassigned = =:=.tpEquals[TFalse]
  val assigned = =:=.tpEquals[TTrue]
}

Scala用法(类型安全):

val v = Builder().withProperty(2).build

Java Usage I(类型安全但丑陋):

int i = Builder$.MODULE$.apply()
        .withProperty(5, Builder$.MODULE$.unassigned())
         .build(Builder$.MODULE$.assigned()); 

Java Usage II(不是类型安全,但更干净,使用@Bridge调用):

static Builder createBuilder() {
  return Builder$.MODULE$.apply();
}
...
int j = createBuilder().withProperty(7).build();