简体   繁体   English

Scala 和 Java 的类型安全生成器库

[英]Type-safe Builder Library for Scala and Java

Below is a type-safe, fluid, builder pattern in Scala as described at http://www.tikalk.com/java/blog/type-safe-builder-scala-using-type-constraints .下面是 Scala 中的类型安全、流畅的构建器模式,如http://www.tikalk.com/java/blog/type-safe-builder-scala-using-type-constraints所述。 It's similar to Builder Library for Scala and Java , but deals specifically with compile-time builder checks.它类似于Scala 和 Java 的构建器库,但专门处理编译时构建器检查。 How can this called from Java?这怎么能从 Java 调用? Can it be done with a clean API for Scala AND Java given the "scala.Predef$$eq$colon$eq" parameters?给定“scala.Predef$$eq$colon$eq”参数,是否可以使用干净的 API 来完成 ScalaJava 参数?

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]
}

You should be able to use this API from Java, with some extra noise compared to the Scala version.您应该可以使用 Java 中的 API,与 Scala 版本相比,它有一些额外的噪音。 A few convenience fields will quiet things a bit:一些方便的字段会让事情变得安静一点:

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

The Java client code should end up looking like Java 客户端代码最终应该看起来像

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

The build method has to check that every property is assigned, so it gets pretty noisy when you generalize to multiple properties: 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(), 
          //...
         );

With some static delegates in a helper class (and some static imports), you should be able to get this down to something like:在帮助器 class 中使用一些 static 代表(以及一些 static 导入),您应该能够将其归结为:

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

OK, thanks to Aaron and ittayd...here is a builder with a fluid API for Scala and Java:好的,多亏了 Aaron 和 ittayd...这是一个带有液体 API 的生成器,用于 Scala 和 Java:

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 Usage (Type Safe): Scala 用法(安全类型):

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

Java Usage I (type safe, but ugly): Java 用法 I(类型安全,但丑陋):

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

Java Usage II (not type safe, but much cleaner, using @Bridge calls): Java 用法 II(不是类型安全,但更简洁,使用 @Bridge 调用):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM