2015-11-03 49 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'一样。 –