在Scala中实现有限状态机(或有限状态传感器)的一般方法是什么?
我经常发现自己需要实现状态机。我的典型实现看起来像
object TypicalFSM { // actually — finite state transducer
type State
case object State1 extends State
case object State2 extends State
type Message
case object Message1 extends Message
type ResultMessage
case object ResultMessage1 extends ResultMessage
}
import TypicalFSM._
class TypicalFSM extends ((Message) =>Seq[ResultMessage]){
var state:State = State1
def apply(message:Message):Seq[ResultMessage] = (state, message) match {
case (State1, Message1) =>
state = State2
Seq(ResultMessage1, ResultMessage2)
}
}
我不喜欢的是可变var
,它使得解决方案线程不安全。 FSM拓扑也不清楚。
如何以功能方式创建FSM?
Akka FSM具有允许将某些数据与状态关联的良好属性,而不仅仅是提供对象名称。这也是值得赞赏的。 (但是,Akka FSM并不总是方便使用,因为它是异步的,有时候有点重量。)
答案 0 :(得分:8)
这可能不是你想要的,但我认为这是一个有趣的概念。
object TypicalFSM {
sealed trait State
final class State1 extends State
final class State2 extends State
sealed trait Message
case class Message1(s: String) extends Message
case class Message2(s: String) extends Message
sealed trait ResultMessage
object ResultMessage1 extends ResultMessage
object ResultMessage2 extends ResultMessage
}
import TypicalFSM._
case class Transformation[M <: Message, From <: State, To <: State](
f:M => Seq[ResultMessage]) {
def apply(m:M) = f(m)
}
object Transformation {
implicit def `message1 in state1` =
Transformation[Message1, State1, State2] { m =>
Seq(ResultMessage1, ResultMessage2)
}
implicit def `message1 in state2` =
Transformation[Message1, State2, State2] { m =>
Seq(ResultMessage1)
}
implicit def `message2 in state2` =
Transformation[Message2, State2, State1] { m =>
Seq(ResultMessage2)
}
}
class TypicalFSM[CurrentState <: State] {
def apply[M <: Message, NewState <: State](message: M)(
implicit transformWith: Transformation[M, CurrentState, NewState]) = {
this.asInstanceOf[TypicalFSM[NewState]] -> transformWith(message)
}
}
用法如下:
def test() = {
val s1 = new TypicalFSM[State1]
// type of s1: TypicalFSM[State1]
val (s2, r1) = s1(Message1("m1"))
// type of s2: TypicalFSM[State2]
val (s3, r2) = s2(Message1("m1"))
// type of s2: TypicalFSM[State2]
val (s4, r3) = s2(Message2("m2"))
// type of s2: TypicalFSM[State1]
// val (s5, r4) = s4(Message2("m2"))
// Fails with:
// 'No transformation available for TypicalFSM.Message2 in TypicalFSM.State1'
// type of s5: TypicalFSM[State1]
}
您的用例将强烈决定此概念中代码的结构。用例确实可以确定您要保留多少类型信息。
我这个概念,因为状态保持使用类型系统,并且在编译时报告非法转换。