在正确使用 scala(和 akka)actor 框架的大多数示例中,人们倾向于从单个 trait 派生每条消息。例如:
trait Message
object Ping extends Message
object Pong extends Message
然而,在 Scala 和 Akka 中,消息接收根本没有类型。有什么理由实现一个共同的特征吗?
这实际上取决于您要实现的目标。例如,我最近构建了一个小型应用程序,它使用具有多种类型 Actor 的 Actor,以及一个或多或少类似于路由器的管理 Actor。Foo
现在,工作参与者可以收到许多不同的消息,例如Bar
和Baz
。如果没有超类型,在管理演员中我必须写这样的东西:
react {
case x:Foo | x:Bar | x:Baz => worker ! x
}
这显然是不必要的冗长。所以在这种情况下,超类型WorkerMessage
会很有意义,因为它简化了您的代码:
react {
case x:WorkerMessage => worker ! x
}
另一方面,这会使消息Foo
,Bar
并且Baz
除了被您的 WorkerActor 使用之外,几乎无法用于任何其他目的。例如,如果您有一条消息Stop
,Init
这可能会很糟糕,因为您需要在整个地方重新定义它。
因此,如果您知道您将只有不传递消息的参与者(也就是说,他们自己处理它们),那么我想您没有超类型就可以了。
我猜人们默认或多或少这样做的原因是,如果您稍后更改代码,则不必在之后创建特征,因为您在一开始就已经这样做了。
就个人而言,我总是尽量避免不必要的开销,所以我可能不会定义超类型,除非我真的需要它。另外,我真的不知道创建超类型是否对性能有任何影响,但我很想知道。
使用scala.actors
(via InputChannel[T]
or Reactor[T]
) 和 Akka ( TypedActor
) 都可以设置传入消息的类型界限;
在大多数示例中,消息扩展为sealed trait
. 这样做有两个原因:
如果你的actor的消息处理程序(部分函数)没有覆盖所有扩展特征的消息,编译器会生成一个警告;
sealed trait
只能在定义了特征的源文件中扩展,因此,客户端不能定义它自己的扩展特征的消息;
这不是强制性的,但它是 OO 设计的东西。为您的应用程序域消息提供一个抽象类型是一个更好的设计。因此,在我们的应用程序代码中处理消息时,您可以获得多态性的好处。
trait Message
object Ping extends Message
objet Pong extends Message
object Stop
例如,如果在您的应用程序的某个地方,您必须处理一堆消息,而不管它们的特定类型(Ping 或 Pong)如何,您将把它们全部视为 Message 类型的对象。这说得通?不 ?