All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.neko233.skilltree.commons.fsm.FSM.kt Maven / Gradle / Ivy

There is a newer version: 0.3.6
Show newest version
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
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy