我开始使用 Akka Typed 来对我的行为进行详尽的模式匹配,这对于每个演员的外部合同都很棒。但是,如果参与者是状态机,则不同的状态很可能具有特定于状态的命令。
我可以将特定于状态的命令隐藏为整个命令的私有成员,如下所示:
sealed trait Command
final case class Add(id: Int) extends Command
private final case object AccumulationTimeout extends Command
private final case object Ack extends Command
但是,我的两个状态accumulating
,emitting
必须处理彼此的命令。我可以使用.receivePartial
或包括一个全部捕获
case _ => Behaviors.unhandled
在这两种情况下,我都丢失了详尽的模式匹配,以确保我正确处理我的状态。
我可以进一步细化命令,如下所示:
sealed trait Command
sealed trait Accumulating extends Command
private final case object AccumulationTimeout extends Accumulating
sealed trait Emitting extends Command
private final case object Ack extends Emitting
final case class Add(id: Int) extends Accumulating with Emitting
有了这个,我可以定义Behavior[Accumulating]
和Behavior[Emitting]
两者都是Behavior[Command]
的,但问题是任何一种行为都无法过渡到另一种行为,因为两者都必须返回自己的类型。
我尝试了.widen
和.narrow
的各种排列都无济于事,并意识到我真正需要的是一种将Behavior
定义为
def receiveMessage[T, V <: T](handler: V => Behavior[T]): Behavior[T] = ???
handler
会让我对窄类型进行详尽的检查V
,对于V
之外的任何消息T
都会返回Behaviors.unhandled
。我似乎无法使类型用于实现这样的功能。
一个想法是对特定于状态的命令子集进行初始匹配。像这样:
def accumulating: Behavior[Command] =
Behaviors.receive {
case acc: Accumulating =>
acc match {
//... complete for the message subtype or compiler fails...
}
case _ =>
// other state subtypes are
Behaviors.unhandled