您可以使用类似于 Scala 函数中的andThen 的模式。
我编译了一个小例子:
import scala.util.{Try, Success, Failure}
type TaskConfiguration = Any
trait Task[-C <: TaskConfiguration, +O <: TaskConfiguration] {
def execute(configuration: C): Option[O]
def andThen[O2 <: TaskConfiguration](secondTask: Task[O, O2]): Task[C, O2] = {
val firstTask = this
new Task[C, O2] {
def execute(configuration: C): Option[O2] =
firstTask.execute(configuration).flatMap(secondTask.execute(_))
}
}
}
// From here on it's the example!
case class UnparsedNumber(value: String)
trait ParsedNumber {
val value: Int
}
case class ParsedPositiveNumber(int: Int) extends ParsedNumber {
val value: Int = int
}
case class HumanReadableNumber(value: String)
val task1 = new Task[UnparsedNumber, ParsedPositiveNumber] {
def execute(configuration: UnparsedNumber): Option[ParsedPositiveNumber] = {
Try(configuration.value.toInt) match {
case Success(i) if i >= 0 => Some(ParsedPositiveNumber(i))
case Success(_) => None
case Failure(_) => None
}
}
}
val task2 = new Task[ParsedNumber, HumanReadableNumber] {
def execute(configuration: ParsedNumber): Option[HumanReadableNumber] = {
if(configuration.value < 1000 && configuration.value > -1000)
Some(HumanReadableNumber(s"The number is $configuration"))
else
None
}
}
val combined = task1.andThen(task2)
println(combined.execute(UnparsedNumber("12")))
println(combined.execute(UnparsedNumber("12x")))
println(combined.execute(UnparsedNumber("-12")))
println(combined.execute(UnparsedNumber("10000")))
println(combined.execute(UnparsedNumber("-10000")))
Try it out!
编辑:
关于您的 cmets,这种方法可能更符合您的要求:
case class Task[-C, +O](f: C => Option[O]) {
def execute(c: C): Option[O] = f.apply(c)
}
case class TaskChain[C, O <: C](tasks: List[Task[C, O]]) {
def run(initial: C): Option[O] = {
def runTasks(output: Option[C], tail: List[Task[C, O]]): Option[O] = {
output match {
case Some(o) => tail match {
case head :: Nil => head.execute(o)
case head :: tail => runTasks(head.execute(o), tail)
case Nil => ??? // This should never happen!
}
case None => None
}
}
runTasks(Some(initial), tasks)
}
}
// Example below:
val t1: Task[Int, Int] = Task(i => Some(i * 2))
val t2: Task[Int, Int] = Task(i => Some(i - 100))
val t3: Task[Int, Int] = Task(i => if(i > 0) Some(i) else None)
val chain: TaskChain[Int, Int] = TaskChain(List(t1, t2, t3))
println(chain.run(100))
println(chain.run(10))
Try it out!
引用:
您需要了解的是,如果您将Tasks 打包在List[Task] 中并将其用作Tasks 的链,则输出必须至少是输入的子类型。 C <: TaskConfiguration 和 O <: C 导致:O <: C <: TaskConfiguration 这也意味着 O <: TaskConfiguration。
如果您不理解其中的任何部分,我很乐意进一步解释。
我希望这会有所帮助。