com.neko233.skilltree.commons.fsm.FSM.kt Maven / Gradle / Ivy
package com.neko233.skilltree.commons.fsm
import org.slf4j.LoggerFactory
import java.util.function.Consumer
/**
* 有限状态机(FSM)类
*/
class FSM {
companion object {
val LOGGER = LoggerFactory.getLogger(this::class.java)!!
}
// 存储状态的映射
private val stateMap = mutableMapOf>()
// 当前状态
lateinit var currentStateId: String
fun firstStateId(stateId: String) {
val state = stateMap.get(stateId)
if (state == null) {
throw IllegalArgumentException("没有这个 stateId = ${stateId}")
}
currentStateId = stateId
}
/**
* 创建并添加一个新的状态到状态机
*
* @param stateId 状态的唯一标识符
* @return 新状态的实例
*/
fun addState(
stateId: String,
stateInitializer: Consumer>
): FSM {
val state = State(this, stateId)
stateInitializer.accept(state)
// 不切换状态, 只记录有这么一个状态
stateMap[stateId] = state
return this
}
fun addState(
stateId: String,
): State {
val state = State(this, stateId)
stateMap[stateId] = state
// 不切换状态, 只记录有这么一个状态
return state
}
/**
* 切换到指定状态
*
* @param stateId 要切换到的状态的唯一标识符
*/
fun changeState(stateId: String) {
val state = stateMap[stateId]
if (state == null) {
LOGGER.error("change state error. stateId = {}", stateId)
return
}
currentStateId = state.stateId
}
/**
* 根据当前数据,执行到下一个状态(下一个状态有可能是一样的)
*
* @param data 新的数据(外部处理过, 再丢进来尝试)
* @return is Next state ok
*/
fun nextState(data: DATA): Boolean {
// 当前状态
val currentState = stateMap.get(currentStateId)
if (currentState == null) {
LOGGER.error("没有这个 state by stateId = ${currentStateId}")
return false
}
// 执行逻辑
currentState.onCurrentStateHandleData?.invoke(this, data)
// 重新计算状态
val stateCalculator = currentState.stateCalculator
?: return false
// 重新计算状态 | 有可能和现在一样
val newStateId = stateCalculator.invoke(data)
// 是否和现有状态相同
val isSameState = newStateId == this.currentStateId
if (isSameState) {
return false
}
// old state exit
currentState.onExitCallback?.invoke(this)
// switch state
val newState = stateMap.get(newStateId)
if (newState == null) {
LOGGER.error("不存在新的状态可以切换, newStateId = {}", newStateId)
return false
}
this.currentStateId = newState.stateId
// new state enter
newState.onEnterCallback?.invoke(this)
return true
}
fun goToFinalState(data: DATA) {
while (true) {
val isNextStateOk = nextState(data)
if (isNextStateOk) {
continue
}
break
}
}
fun setState(stateId: String) {
val state = stateMap.get(stateId)
if (state == null) {
throw IllegalArgumentException("没有这个 state by stateId = ${stateId}")
}
this.currentStateId = state.stateId
}
/**
* 状态类,包含状态的回调函数
*/
data class State(
var fsm: FSM,
var stateId: String
) {
// 根据 data 计算当前状态
internal var stateCalculator: ((data: DATA) -> String)? = null
// 当前状态如何处理数据
internal var onCurrentStateHandleData: ((FSM, DATA) -> Unit)? = null
// Lifecycle-enter
internal var onEnterCallback: ((FSM) -> Unit)? = null
// Lifecycle-exit
internal var onExitCallback: ((FSM) -> Unit)? = null
override fun toString(): String {
return stateId
}
/**
* 如何计算状态
*
* @param calculator 条件状态选择器
* @return stateId: String
*/
fun howToCalculateState(calculator: (data: DATA) -> String): State {
stateCalculator = calculator
return this
}
/**
* 设置状态的进入回调函数
*
* @param callback 进入回调函数
* @return 当前状态的实例
*/
fun onEnter(callback: (FSM) -> Unit): State {
onEnterCallback = callback
return this
}
/**
* 当前状态下, 需要对 data 做什么操作
* action 中需要自己处理【幂等问题】, 例如【检查订单是否存在 + 乐观所更新】
*
* @param action 执行回调函数
* @return 当前状态的实例
*/
fun onCurrentStateHandleData(action: (FSM, DATA) -> Unit): State {
onCurrentStateHandleData = action
return this
}
/**
* 设置状态的退出回调函数
*
* @param callback 退出回调函数
* @return 当前状态的实例
*/
fun onExit(callback: (FSM) -> Unit): State {
onExitCallback = callback
return this
}
fun done(): FSM {
return fsm
}
}
}