2011-06-14 38 views
4

下面是在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的乾淨API Java來完成嗎?適用於Scala和Java的類型安全的Builder庫

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

回答

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()); 
+0

是,在Java相當嘈雜,但回答了這個問題。可能會犧牲Java版本中的類型安全......但是可能@Bridge用於提供純Java版本並刪除* assigned()參數? – eptx 2011-06-15 19:08:31

+0

使用通過'null'的橋接方法,就像ittayd建議的一樣(http://www.tikalk.com/incubator/blog/creating-java-api-scala-using-bridge#comments)可以工作,但它肯定犧牲型號安全。這是因爲'null'是矛盾的一個實例:'TFalse =:= TTrue'。 – 2011-06-15 21:21:10

+1

我還應該指出,這個構建器模式的類型安全性並不依賴於隱式搜索。相反,它依賴於不可能用兩個不相等的類型參數實例化'=:='類(即'null'是唯一的矛盾)。 – 2011-06-15 21:42:05

3

確定,這要歸功於亞倫和ittayd ...這裏是斯卡拉和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] 
} 

斯卡拉用途(類型安全):

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();