2015-11-03 47 views
1

我想構建一個模式,用戶可以實現一個簡單的接口,它接受一種類型的對象並返回另一種類型,然後也有一些類型的鏈對象,它由一個序列這些轉換。斯卡拉類型安全可組裝的生成器鏈與仿製藥

我遇到的問題是在Scala中獲得正確的泛型類型 - 我的Scala-foo還沒有那麼高,所以任何建議都是最受讚賞的,包括告訴我我正在做這個錯誤的/非scala的方式!

trait Builder[INPUT, OUTPUT] { 

    var input: Class[INPUT] 
    var output: Class[OUTPUT] 
    def process(input: RDD[INPUT]): RDD[OUTPUT] 
} 


class ComposableBuilder[INPUT, OUTPUT](input: Class[INPUT], output: Class[OUTPUT], phases: Seq[Phase[Any, Any]]) { 

    def appendBuilder[U](phase: Phase[OUTPUT, U]): ComposableBuilder[INPUT, U] = { 
    new ComposableBuilder[INPUT, U](input.class, phase.output.class, phases :+ phase) 
    } 
} 

這樣一個例子用法是:

ComposableBuilder(Seq(
    ModelEnricher(), 
    CollateRecordsByKey(), 
    RecordBuilder(), 
)).execute(input) 

所以很明顯有一個隱含的約束,對於建設者在該序列的任何連續對builder[0].output == builder[1].input

回答

4

我不知道爲什麼你使用存儲Class信息的變量。該解決方案應該是簡單得多隻是使用標準的仿製藥:

trait Builder[A,B] { 
    def process(input: A): B 
} 

case class ComposedBuilder[A,B,C](b1: Builder[A,B], b2: Builder[B,C]) extends Builder[A,C] { 
    def process(input: A): C = b2.process(b1.process(input)) 
} 

然後你就可以讓你的建設者:

object Int2DoubleBuilder extends Builder[Int, Double] { def process(input: Int): Double = input.toDouble } 
object Double2StringBuilder extends Builder[Double,String] { def process(input: Double): String = f"$input%.2f" } 
object StringPadBuilder  extends Builder[String,String] { def process(input: String): String = "000" + input } 

,並利用它們:

val builder = ComposedBuilder(ComposedBuilder(Int2DoubleBuilder, Double2StringBuilder), StringPadBuilder) 
builder.process(423) 
// 000423.00 

薩米爾的評論品牌好點。如果你的情況確實如此簡單,那麼你可以使用內置的Function1特性免費獲得一些不錯的功能。所以,你可以有每個製造商實現A => B功能:

object Int2DoubleBuilder extends (Int => Double) { def apply(input: Int): Double = input.toDouble } 
object Double2StringBuilder extends (Double => String) { def apply(input: Double): String = f"$input%.2f" } 
object StringPadBuilder  extends (String => String) { def apply(input: String): String = "000" + input } 

,並利用它們:

val builder = Int2DoubleBuilder andThen Double2StringBuilder andThen StringPadBuilder 
builder(423) 
// 000423.00 
+3

同意,但值得注意的是,你的'Builder'對象其實只是類型的函數'A => B'。並且可以使用'compose'方法來組合函數,就像'ComposeBuilder'一樣。 –