状态机是古老的计算机理论,在游戏开发、嵌入式开发、网络协议等领域,获得普遍地使用。java
状态机:它是一个有向图形,由一组节点和一组相应的转移函数组成。状态机经过响应一系列事件而“运行”。每一个事件都在属于“当前” 节点的转移函数的控制范围内,其中函数的范围是节点的一个子集。函数返回“下一个”(也许是同一个)节点。这些节点中至少有一个必须是终态。当到达终态, 状态机中止。android
有限状态机,(英语:Finite-state machine, FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动做等行为的数学模型。git
如下是对状态机抽象定义github
肯定有限状态自动机或肯定有限自动机(英语:deterministic finite automaton, DFA)是一个能实现状态转移的自动机对于一个给定的属于该自动机的状态和一个属于该自动机字母表的字符,它都能根据事先给定的转移函数转移到下一个状态(这个状态能够是先前那个状态)。后端
DFA 是 FSM 的一种,与 DFA 对应的还有 NFA(非肯定性有限自动机)。数组
DFA 的特性:bash
之前我写过的一篇文章《一个快速分析android app使用了哪些sdk的工具》 曾经使用过DFA。网络
层次状态机(英语:Hierarchical State Machine)是状态机理论中的一种层次结构的模型,各个状态按照树状层次结构组织起来,状态图是层次结构的,也就是说每一个状态能够拥有子状态。app
当 FSM 状态太多的时候,能够将状态分类,并抽离出来。同类型的状态作为一个状态机,而后再作一个大的状态机,来维护这些子状态机。框架
github 地址:github.com/fengzhizi71…
用于保存管理 State 对象实例,表示 State 实例所处的环境。
interface StateContext {
fun getEvent(): BaseEvent
fun getSource(): BaseState
fun getTarget(): BaseState
fun getException(): Exception?
fun setException(exception: Exception)
fun getTransition(): Transition
}
复制代码
构成状态机的基本单位,状态机在任何特定时间均可处于某一状态。
class State(val name: BaseState) {
private val transitions = hashMapOf<BaseEvent, Transition>() // 存储当前 State 相关的全部 Transition
private val stateActions = mutableListOf<StateAction>() // 当前 State 相关的全部 Action
/** * 当一个 Event 被状态机系统分发的时候,状态机用 Action 来进行响应 * 状态转换可使用 F(S, E) -> (A, S’) 表示 * * @param event: 触发事件 * @param targetState: 下一个状态 * @param guard: 断言接口,为了转换操做执行后检测结果是否知足特定条件从一个状态切换到某一个状态 * @param init */
fun transition(event: BaseEvent, targetState: BaseState, guard: Guard?=null, init: Transition.() -> Unit):State {
val transition = Transition(event, this.name, targetState, guard)
transition.init()
if (transitions.containsKey(event)) { // 同一个 Event 不能对应多个 Transition,即 State 只能经过一个 Event 而后 Transition 到另外一个 State
throw StateMachineException("Adding multiple transitions for the same event is invalid")
}
transitions[event] = transition
return this
}
/** * State 执行的 Action */
fun action(action: StateAction) {
stateActions.add(action)
}
/** * 进入 State 并执行全部的 Action */
fun enter() {
stateActions.forEach {
it.invoke(this)
}
}
/** * 经过 Event 获取 Transition */
fun getTransitionForEvent(event: BaseEvent): Transition = transitions[event]?:throw IllegalStateException("Event $event isn't registered with state ${this.name}")
override fun toString(): String = name.javaClass.simpleName
}
复制代码
从一个状态切换到另外一个状态。
class Transition(private val event: BaseEvent, private val sourceState: BaseState, private val targetState: BaseState, private var guard:Guard?= null) {
private val actions = mutableListOf<TransitionAction>()
/** * 是否转换 * @param context */
fun transit(context: StateContext): Boolean {
executeTransitionActions(context)
return context.getException() == null
}
/** * 执行 Transition 的 Action */
private fun executeTransitionActions(context: StateContext) {
actions.forEach {
try {
it.invoke(this)
} catch (e:Exception) {
context.setException(e)
return
}
}
}
/** * 添加一个 action,在状态转换时执行(时间点是在状态转换以前) */
fun action(action: TransitionAction) {
actions.add(action)
}
/** * 转换状态 */
fun applyTransition(getNextState: (BaseState) -> State): State = getNextState(targetState)
/** * 设置检测条件,判断是否知足状态转换的条件,知足则执行状态转换 */
fun guard(guard: Guard) {
this.guard = guard
}
fun getGuard():Guard? = guard
fun getSourceState(): BaseState = sourceState
fun getTargetState(): BaseState = targetState
override fun toString(): String = "${sourceState.javaClass.simpleName} transition to ${targetState.javaClass.simpleName} on ${event.javaClass.simpleName}"
}
复制代码
class StateMachine private constructor(private val initialState: BaseState) {
private lateinit var currentState: State // 当前状态
private val states = mutableListOf<State>() // 状态列表
private val initialized = AtomicBoolean(false) // 是否初始化
private var globalInterceptor: GlobalInterceptor?=null
private val transitionCallbacks: MutableList<TransitionCallback> = mutableListOf()
/** * 设置状态机全局的拦截器,使用时必需要在 initialize() 以前 * @param event: 状态机全局的拦截器 */
fun interceptor(globalInterceptor: GlobalInterceptor):StateMachine {
this.globalInterceptor = globalInterceptor
return this
}
/** * 初始化状态机,并进入初始化状态 */
fun initialize() {
if(initialized.compareAndSet(false, true)){
currentState = getState(initialState)
globalInterceptor?.stateEntered(currentState)
currentState.enter()
}
}
/** * 向状态机添加 State */
fun state(stateName: BaseState, init: State.() -> Unit):StateMachine {
val state = State(stateName)
state.init()
states.add(state)
return this
}
/** * 经过状态名称获取状态 */
private fun getState(stateType: BaseState): State = states.firstOrNull { stateType.javaClass == it.name.javaClass } ?: throw NoSuchElementException(stateType.javaClass.canonicalName)
/** * 向状态机发送 Event,执行状态转换 */
@Synchronized
fun sendEvent(e: BaseEvent) {
try {
val transition = currentState.getTransitionForEvent(e)
globalInterceptor?.transitionStarted(transition)
val stateContext: StateContext = DefaultStateContext(e, transition, transition.getSourceState(), transition.getTargetState())
//状态转换以前执行的 action(Transition 内部的 action), action执行失败表示不接受事件,返回false
val accept = transition.transit(stateContext)
if (!accept) {
//状态机发生异常
globalInterceptor?.stateMachineError(this, StateMachineException("状态转换失败,source ${currentState.name} -> target ${transition.getTargetState()} Event ${e}"))
return
}
val guard = transition.getGuard()?.invoke()?:true
if (guard) {
val state = transition.applyTransition { getState(stateContext.getTarget()) }
val callbacks = transitionCallbacks.toList()
globalInterceptor?.apply {
stateContext(stateContext)
transition(transition)
stateExited(currentState)
}
callbacks.forEach { callback ->
callback.enteringState(this, stateContext.getSource(), transition, stateContext.getTarget())
}
state.enter()
callbacks.forEach { callback ->
callback.enteredState(this, stateContext.getSource(), transition, stateContext.getTarget())
}
globalInterceptor?.apply {
stateEntered(state)
stateChanged(currentState,state)
transitionEnded(transition)
}
currentState = state
} else {
println("$transition 失败")
globalInterceptor?.stateMachineError(this, StateMachineException("状态转换时 guard [${guard}], 状态 [${currentState.name}],事件 [${e.javaClass.simpleName}]"))
}
} catch (exception:Exception) {
globalInterceptor?.stateMachineError(this, StateMachineException("This state [${this.currentState.name}] doesn't support transition on ${e.javaClass.simpleName}"))
}
}
@Synchronized
fun getCurrentState(): BaseState = this.currentState.name
/** * 注册 TransitionCallback */
fun registerCallback(transitionCallback: TransitionCallback) = transitionCallbacks.add(transitionCallback)
/** * 取消 TransitionCallback */
fun unregisterCallback(transitionCallback: TransitionCallback) = transitionCallbacks.remove(transitionCallback)
companion object {
fun buildStateMachine(initialStateName: BaseState, init: StateMachine.() -> Unit): StateMachine {
val stateMachine = StateMachine(initialStateName)
stateMachine.init()
return stateMachine
}
}
}
复制代码
在 StateMachine 中,包含了一个全局的 GlobalInterceptor 和 一个 TransitionCallback 的列表。
可以监听 State、Transition、StateContext 以及异常。
interface GlobalInterceptor {
/** * 进入某个 State */
fun stateEntered(state: State)
/** * 离开某个 State */
fun stateExited(state: State)
/** * State 发生改变 * @param from: 当前状态 * @param to: 下一个状态 */
fun stateChanged(from: State, to: State)
/** * 触发 Transition */
fun transition(transition: Transition)
/** * 准备开始 Transition */
fun transitionStarted(transition: Transition)
/** * Transition 结束 */
fun transitionEnded(transition: Transition)
/** * 状态机异常的回调 */
fun stateMachineError(stateMachine: StateMachine, exception: Exception)
/** * 监听状态机上下文 */
fun stateContext(stateContext: StateContext)
}
复制代码
只能监听 Transition 发生的变化,也就是进入 State、离开 State。
interface TransitionCallback {
fun enteringState( stateMachine: StateMachine, currentState: BaseState, transition: Transition, targetState: BaseState )
fun enteredState( stateMachine: StateMachine, previousState: BaseState, transition: Transition, currentState: BaseState )
}
复制代码
定义了状态内部执行的 action、Transition 执行的 action、以及是否执行 Transition 的断言。
typealias StateAction = (State) -> Unit
typealias TransitionAction = (Transition) -> Unit
typealias Guard = ()->Boolean
复制代码
经过对 StateMachine 增长扩展属性 enterTransitionObservable、exitTransitionObservable 能够监听到进入 State、离开 State 发生的变化。
val StateMachine.stateObservable: Observable<TransitionEvent>
get() = Observable.create { emitter ->
val rxCallback = RxStateCallback(emitter)
registerCallback(rxCallback)
emitter.setCancellable {
unregisterCallback(rxCallback)
}
}
val StateMachine.enterTransitionObservable: Observable<TransitionEvent.EnterTransition>
get() = stateObservable
.filter { event -> event is TransitionEvent.EnterTransition }
.map { event -> event as TransitionEvent.EnterTransition }
val StateMachine.exitTransitionObservable: Observable<TransitionEvent.ExitTransition>
get() = stateObservable
.filter { event -> event is TransitionEvent.ExitTransition }
.map { event -> event as TransitionEvent.ExitTransition }
复制代码
举一个简单的例子,用 FSM 来模拟用户从初始状态,到吃饭的状态,最后到看电视的状态。
fun main() {
val sm = StateMachine.buildStateMachine(Initial()) {
state(Initial()) {
action {
println("Entered [$it] State")
}
transition(Cook(), Eat()) {
action {
println("Action: Wash Vegetables")
}
action {
println("Action: Cook")
}
}
}
state(Eat()) {
action {
println("Entered [$it] State")
}
transition(WashDishes(), WatchTV()) {
action {
println("Action: Wash Dishes")
}
action {
println("Action: Turn on the TV")
}
}
}
state(WatchTV()) {
action {
println("Entered [$it] State")
}
}
}
sm.initialize()
sm.sendEvent(Cook())
sm.sendEvent(WashDishes())
}
复制代码
执行结果:
Entered [Initial] State
Action: Wash Vegetables
Action: Cook
Entered [Eat] State
Action: Wash Dishes
Action: Turn on the TV
Entered [WatchTV] State
复制代码
之因此开发一款 FSM 框架,主要是为了重构公司的项目。趁疫情期间正好把之前的项目捋一捋。目前打算将这个 FSM 应用在咱们的移动端和后端的项目上。
参考资料: