4

下面是 Scala 中类型安全、流畅的构建器模式,如http://www.tikalk.com/java/blog/type-safe-builder-scala-using-type-constraints中所述。它类似于Scala 和 Java 的 Builder Library,但专门处理编译时构建器检查。这怎么能从Java调用?在给定“scala.Predef$$eq$colon$eq”参数的情况下,是否可以使用适用于 Scala和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]
}
4

2 回答 2

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());
于 2011-06-14T21:35:02.050 回答
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 用法 I(类型安全,但丑陋):

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

Java 用法 II(不是类型安全的,但更简洁,使用 @Bridge 调用):

static Builder createBuilder() {
  return Builder$.MODULE$.apply();
}
...
int j = createBuilder().withProperty(7).build();
于 2011-06-16T22:02:52.893 回答