我在那里,我正在尝试将 Command 和责任链模式与Scala风格相结合。
基本上,我希望有一个Executor
通过链传递命令并返回结果。 命令是返回T
:
class class Invoker {
type Command[T] = () => T
val handlers = new mutable.ListBuffer[PartialFunction[() => T, T]]
def invoke[T](command: => T): Future[T] = Future {
handlers.find(_.isDefinedAt(command)).map(_.apply(command))
}
}
但是,因为我是scala初学者,所以handlers
列表的泛型类型存在问题。我无法弄清楚如何在T
的声明中定义handlers
,以便invoke
命令返回正确的类型(应该是T
)
有人可以帮我实现这种模式吗?
答案 0 :(得分:2)
有几个粗略的地方,但我认为你最接近你想要的是(虽然,它不起作用,见下文):
import scala.collection.mutable
import scala.concurrent.Future
object Invoker {
val handlers = new mutable.ListBuffer[PartialFunction[Any, Any]]
def invoke[T](command: () => T): Future[T] = Future {
handlers.collectFirst {
case pf if pf.isDefinedAt(command) => pf(command)
}.fold(throw new Exception("failure")) {
_.asInstanceOf[T]
}
}
}
然而,
它不起作用,因为部分功能或更具体的模式匹配肯定不会像你期望的那样工作Function0
您通过删除丢失了大部分类型信息,并且必须依赖于您对部分功能的了解。
在scala中,调用asInstanceOf
的需要是一个很好的指标,表明可以做得更好。
@ 1
当您定义与Function0
匹配的部分函数列表时,例如:
val T1: () => Int = () => 1
val T2: () => Int = () => 2
val T3: () => Int = () => 3
val pfs: Seq[PartialFunction[Any, Any]] = Seq(
PartialFunction[Any, Any] {
case T1 => T1()
},
PartialFunction[Any, Any] {
case T2 => T2()
},
PartialFunction[Any, Any] {
case T3 => T3()
}
)
尝试查找任何函数文字的匹配项将导致MatchError:
def invoke[T](c: () => T): T = {
pfs.collectFirst {
case pf if pf.isDefinedAt(c) => pf(c)
}.fold(throw new Exception("failure")) {
_.asInstanceOf[T]
}
}
invoke(() => 1) |-> scala.MatchError: <function0> (of class abc.A$A290$A$A290$$anonfun$ti1$1)
这只有在为允许的函数定义常量并且在调用invoke时才使用这些常量时才有效。
您可以使用Invoker
对象定义它们:
object Invoker {
val SomeCommand = () => 5 + 5
val AnotherCommand = () => 5 * 5
}
但这完全可以消除任何灵活性。
<强>最后:强>
如果您希望能够执行任何 Command ,那么为什么还要保留处理程序列表?
object Invoker {
def invoke[T](command: () => T): Future[T] = Future {
command()
}
}
应该足够了。