Я хочу построить шаблон конвейера с помощью Scala.Я хотел бы после того, как я напишу объекты конвейера, они могут быть соединены вместе следующим образом:
Pipeline1 :: Pipeline2 :: Pipeline3 ...
Я до сих пор экспериментировал с несколькими идеями.Некоторые работают, а некоторые нет.Но ни один из них, кажется, полностью не избавился от стандартного кода.Ниже приведено следующее.
Сначала определите абстрактный класс Pipeline и Source:
// 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)
Затем я создал два конвейера и попытался связать их вместе
// 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)
}
Это основной класс, в котором связаны два конвейера.
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())
}
}
Так что этот код работает.Но мне пришлось бы повторять код в сопутствующем объекте TimesTen в каждом написанном мной классе конвейера.Это конечно не желательно.Есть ли лучший способ сделать это?Отражение может сработать, но я слышал о нем плохие вещи, например, что-либо с отражением - плохой дизайнЯ также не уверен насчет поддержки отражений в Scala.
Спасибо за ваше время.
Обновление : я разработал эту игрушечную задачу, чтобы ее было легче понять.Как общее решение, и как требует мое приложение, каждый объект конвейера имеет состояние, которое идеально инкапсулируется в самом объекте, а не подвергается воздействию любого другого конвейера.Я изменил код выше, чтобы отразить это.Хотелось бы, чтобы могло быть объектно-ориентированное решение.Я все еще экспериментирую и сообщу вам, если я найду один.
Обновление 2 : После некоторых мыслей, я думаю, что идея конвейера на самом деле является просто обобщенной функцией, которая содержит некоторыевнутренние состояния, а также способность составлять функцию Function0
с функцией Function1
.В Scala класс Function0
не имеет метода compose()
или andThen()
.