Wie elegant Umsetzung des pipeline-Muster mit Scala

Ich bin auf der Suche nach Aufbau einer pipeline-Muster mit Scala. Ich Wünsche, nachdem ich das schreiben der pipeline-Objekte, Sie könnten miteinander verbunden werden, wie dies:

Pipeline1 :: Pipeline2 :: Pipeline3 ...

Habe ich experimentierte mit ein paar Ideen so weit. Einige arbeiten und einige nicht. Aber keiner von Ihnen scheint, um vollständig loszuwerden boilerplate-code. Im folgenden ist der nächste, den ich bekommen habe.

Definieren Sie zunächst die Rohrleitung und die Source-abstrakte Klasse:

//I is the input type and O is the output type of the pipeline
abstract class Pipeline[I, +O](p: Pipeline[_, _ <: I]) {

  val source = p
  val name: String
  def produce(): O
  def stats():String
}
abstract class Source[+T] extends Pipeline[AnyRef, T](null)

Weiter, ich habe zwei pipelines und versuchen, Sie zu verknüpfen

//this creates a random integer
class RandomInteger extends Source[Int] {
  override val name = "randInt"

  def produce() = {
    scala.Math.round(scala.Math.random.asInstanceOf[Float] * 10)
  }

  def stats()="this pipeline is stateless"
}

//multiply it by ten
class TimesTen(p: Pipeline[_, Int]) extends Pipeline[Int, Int](p) {
  private var count = 0 //this is a simple state of the pipeline
  override val name = "Times"
  def produce = {
    val i = source.produce()
    count += 1 //updating the state
    i * 10
  }
  def stats() = "this pipeline has been called for " + count + " times"
}

object TimesTen {
  //this code achieves the desired connection using ::
  //but this has to be repeated in each pipeline subclass. 
  //how to remove or abstract away this boilerplate code? 
  def ::(that: Pipeline[_, Int]) = new TimesTen(that)
}

Dies ist die main-Klasse, wo die beiden Leitungen miteinander verbunden sind.

object Pipeline {
  def main(args: Array[String]) {
    val p = new RandomInteger() :: TimesTen
    println(p.source)
    for (i <- 0 to 10)
      println(p.produce())
    println(p.stats())
  }
}

Damit dieser code funktioniert. Aber ich würde wiederholen Sie den code in die TimesTen companion Objekts in jeder pipeline-Klasse, die ich Schreibe. Dies ist sicherlich nicht wünschenswert. Gibt es eine bessere Möglichkeit, dies zu tun? Reflexion funktionieren könnte, aber ich habe gehört, schlechte Dinge über Sie, wie alles was mit Reflexion ist schlechtes design. Ich bin auch unsicher, Scala support für die Reflexion.

Vielen Dank für Ihre Zeit.

Update: ich habe dieses Spielzeug-problem, um es einfach zu verstehen. Als Allgemeine Lösung, da meine Anwendung benötigt jede pipeline-Objekt, hat einen Zustand, der idealerweise gekapselt innerhalb des Objekts selbst eher ausgesetzt als jede andere pipeline. Ich veränderte den code oben, um diese zu reflektieren. Ich wünschte, es könnte sein, ein Objekt-basierte Lösung. Ich bin noch am Experimentieren und werde Sie wissen lassen, wenn ich eins finden.

Update 2: Nach einigen Gedanken, die ich denke, die Idee der pipeline ist wirklich nur eine verallgemeinerte Funktion, die enthält einige interne Zustände sowie die Fähigkeit zum verfassen einer Function0 Funktion mit einem Function1 Funktion. In Scala, die Function0 Klasse nicht die compose() oder andThen() Methode.

InformationsquelleAutor Albert Li | 2012-03-07
Schreibe einen Kommentar