FSM(状态机)的JAVA实现

前言

有限状态机(英语:finite-state machine,縮寫:FSM)又稱有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。(FROM WIKI)

FSM的核心和作用

状态机中的核心内容:有限个状态、通过外部操作引起状态的转移。
用来对状态的流转进行解耦,使代码逻辑更加清楚和更容易维护

FSM的组成和分类

组成

  • 现态:是指当前所处的状态。
  • 条件:又称为事件。当一个条件被满足,可能将会触发一个动作,或者执行一次状态的迁移。
  • 动作:条件满足后执行的动作行为。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
  • 次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。

所有的状态转换都可以概括为:F(S, E) -> (A, S’),即如果当前状态为S,接收到一个事件E,则执行动作A,同时状态转换为下个状态S’。

分类

  • F(S) -> (A, S’) 型状态机:下一状态只由当前状态决定
  • F(S, E) -> (A, S’) 型状态机:下一状态不但与当前状态有关,还与当前输入值有关

通过映射表实现状态机

动作接口:

public interface Action {

    boolean action(Context context);

}

映射表数据结构:

@Setter
@Getter
public class ActionMapping {

    /**
     * 当前状态
     */
    private State currentState;

    /**
     * 次态
     */
    private State nextState;

    /**
     * 动作
     */
    private Action action;

    /**
     * 事件
     */
    private Event event;


    public static ActionMapping ofMap(State currentState, Event event, State nextState, Action action) {
        return new ActionMapping(currentState, event, nextState, action);
    }

    private ActionMapping(State currentState, Event event, State nextState, Action action) {
        this.currentState = currentState;
        this.nextState = nextState;
        this.action = action;
        this.event = event;
    }
}

动作中需要使用的上下文参数:

@Getter
@Setter
@AllArgsConstructor
public class Context {

    private String param;


}

事件枚举:

public enum Event {

    /**
     * 审批通过
     */
    APPROVE_PASS,

    /**
     * 审批拒绝
     */
    APPROVE_REFUSED,

    /**
     * 复核通过
     */
    RECHECK_PASS,

    /**
     * 复核不通过
     */
    RECHECK_REFUSED;

}

状态枚举:

public enum State {

    /**
     * 待审核
     */
    APPROVE,

    /**
     * 拒绝
     */
    REFUSED,

    /**
     * 同意
     */
    PASS;

}

状态转移表:

@Setter
@Getter
public class ActionMapping {

    /**
     * 当前状态
     */
    private State currentState;

    /**
     * 次态
     */
    private State nextState;

    /**
     * 动作
     */
    private Action action;

    /**
     * 事件
     */
    private Event event;


    public static ActionMapping ofMap(State currentState, Event event, State nextState, Action action) {
        return new ActionMapping(currentState, event, nextState, action);
    }

    private ActionMapping(State currentState, Event event, State nextState, Action action) {
        this.currentState = currentState;
        this.nextState = nextState;
        this.action = action;
        this.event = event;
    }
}

状态机:

public class Machine {

    /**
     * 状态转移表
     */
    private List<ActionMapping> mappings = new ArrayList<>();

    {
        //F(APPROVE,APPROVE_PASS)->(PASS,ApprovePassAction)
        mappings.add(ActionMapping.ofMap(APPROVE, APPROVE_PASS, PASS, new ApprovePassAction()));

        //F(APPROVE,APPROVE_REFUSED)->(REFUSED,ApproveRefusedAction)
        mappings.add(ActionMapping.ofMap(APPROVE, APPROVE_REFUSED, REFUSED, new ApproveRefusedAction()));

        //F(REFUSED,RECHECK_PASS)->(PASS,RecheckPassAction)
        mappings.add(ActionMapping.ofMap(REFUSED, RECHECK_PASS, PASS, new RecheckPassAction()));

        //F(REFUSED,RECHECK_REFUSED)->(REFUSED,RecheckRefusedAction)
        mappings.add(ActionMapping.ofMap(REFUSED, RECHECK_REFUSED, REFUSED, new RecheckRefusedAction()));

    }

    public boolean transform(State currentState, Event event, Context context) {
        ActionMapping actionMapping = getMapping(currentState, event);
        if (null == actionMapping) {
            throw new RuntimeException("未找到相应的映射");
        }
        Action action = actionMapping.getAction();
        action.action(context);
        return true;
    }

    private ActionMapping getMapping(State currentState, Event event) {
        if (mappings.size() > 0) {
            for (ActionMapping n : mappings) {
                if (n.getCurrentState().equals(currentState) && n.getEvent().equals(event)) {
                    return n;
                }
            }
        }
        return null;
    }

}

审批通过动作的实现:


    @Override
    public boolean action(Context context) {

        System.out.println(MessageFormat.format("审批人{0}审批了价格,审批结果为通过", context.getParam()));
        //TODO 将审批状态更新为已审核通过
        return true;
    }
}

审批拒绝动作的实现:

public class ApproveRefusedAction implements Action {
    @Override
    public boolean action(Context context) {
        System.out.println(MessageFormat.format("审批人{0}审批了价格,审批结果为拒绝", context.getParam()));
        //TODO 将审批状态更新为审核拒绝
        return true;
    }
}

复核通过动作的实现:

public class RecheckPassAction implements Action {
    @Override
    public boolean action(Context context) {
        System.out.println(MessageFormat.format("审批人{0}对未审核通过的价格进行复核,审批结果为通过", context.getParam()));
        //TODO 将审批状态更新为审核通过
        return true;
    }
}

复核拒绝的动作实现

public class RecheckPassAction implements Action {
    @Override
    public boolean action(Context context) {
        System.out.println(MessageFormat.format("审批人{0}对未审核通过的价格进行复核,审批结果为通过", context.getParam()));
        //TODO 将审批状态更新为审核通过
        return true;
    }
}

测试类:

public class Test {

    public static void main(String[] args) {
        Machine machine = new Machine();

        machine.transform(APPROVE,APPROVE_REFUSED,new Context("咲夜"));
        machine.transform(REFUSED,RECHECK_REFUSED,new Context("咲夜"));
        machine.transform(REFUSED,RECHECK_PASS,new Context("帕秋莉"));
    }
}

输出:
在这里插入图片描述

squirrel状态机框架

就像松鼠一样,小巧,灵活,智能,警觉和可爱的动物,squirrel基础旨在为企业使用提供轻量级,高度灵活和可扩展,可诊断,易于使用和类型安全的Java状态机实现。
squirrel文档:https://www.yangguo.info/2015/02/01/squirrel/
文档中很多已经介绍的十分清楚明白了,我这里就不做过多赘述,只写一个例子。

事件枚举:

public enum Event {

    /**
     * 审批通过
     */
    APPROVE_PASS,

    /**
     * 审批拒绝
     */
    APPROVE_REFUSED,

    /**
     * 复核通过
     */
    RECHECK_PASS,

    /**
     * 复核不通过
     */
    RECHECK_REFUSED;

}

状态枚举:

public enum State {

    /**
     * 待审核
     */
    APPROVE,

    /**
     * 拒绝
     */
    REFUSED,

    /**
     * 同意
     */
    PASS;

}

上下文参数:

@Getter
@Setter
@AllArgsConstructor
public class Context {

    private String param;


}

状态机

package com.lg.state.squirrel;

import com.lg.state.Context;
import com.lg.state.Event;
import com.lg.state.State;
import org.squirrelframework.foundation.fsm.impl.AbstractStateMachine;

import java.text.MessageFormat;

public class StateMachine extends AbstractStateMachine<StateMachine, State, Event, Context> {

    private void approvePassAction(State from, State to, Event event, Context context) {
        System.out.println(MessageFormat.format("审批人{0}审批了价格,审批结果为通过", context.getParam()));
        //TODO 将审批状态更新为已审核通过
    }

    private void approveRefusedAction(State from, State to, Event event, Context context) {
        System.out.println(MessageFormat.format("审批人{0}审批了价格,审批结果为拒绝", context.getParam()));
        //TODO 将审批状态更新为审核拒绝
    }

    private void recheckPassAction(State from, State to, Event event, Context context) {
        System.out.println(MessageFormat.format("审批人{0}对未审核通过的价格进行复核,审批结果为通过", context.getParam()));
        //TODO 将审批状态更新为审核通过
    }

    private void recheckRefusedAction(State from, State to, Event event, Context context) {
        System.out.println(MessageFormat.format("审批人{0}对未审核通过的价格进行复核,审批结果为不通过", context.getParam()));
        //TODO 将审批状态更新为审核不通过
    }
}

调用入口示例:

 public static void main(String[] args) {

        StateMachineBuilder<StateMachine, State, Event, Context> builder =
                StateMachineBuilderFactory.create(StateMachine.class, State.class, Event.class, Context.class);

        /**
         * 状态转移表
         */
        //F(APPROVE,APPROVE_PASS)->(PASS,approvePassAction)
        builder.externalTransition().from(APPROVE).to(PASS).on(APPROVE_PASS).callMethod("approvePassAction");

        //F(APPROVE,APPROVE_REFUSED)->(REFUSED,ApproveRefusedAction)
        builder.externalTransition().from(APPROVE).to(REFUSED).on(APPROVE_REFUSED).callMethod("approveRefusedAction");

        //F(REFUSED,RECHECK_PASS)->(PASS,RecheckPassAction)
        builder.externalTransition().from(REFUSED).to(PASS).on(RECHECK_PASS).callMethod("recheckPassAction");

        //F(REFUSED,RECHECK_REFUSED)->(REFUSED,RecheckRefusedAction)
        builder.externalTransition().from(REFUSED).to(REFUSED).on(RECHECK_REFUSED).callMethod("recheckRefusedAction");

        StateMachine machine = builder.newStateMachine(APPROVE);

        Context patchouli = new Context("patchouli");
        Context xiaoye = new Context("咲夜");

        machine.start();

        //patchouli审批拒绝
        machine.fire(APPROVE_REFUSED,patchouli);

        //xiaoye复核成功
        machine.fire(RECHECK_PASS,xiaoye);

    }

结果:
在这里插入图片描述

引用

  • 2
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
下面是一个简单的FSM状态机示例代码(使用Python编写): ```python class State: def __init__(self, name): self.name = name def on_enter(self): pass def on_exit(self): pass def handle_event(self, event): pass class StateMachine: def __init__(self, initial_state): self.current_state = initial_state def transition_to(self, new_state): self.current_state.on_exit() self.current_state = new_state self.current_state.on_enter() def handle_event(self, event): self.current_state.handle_event(event) # 示例状态 class IdleState(State): def on_enter(self): print("进入空闲状态") def on_exit(self): print("退出空闲状态") def handle_event(self, event): if event == "start": print("开始任务") return "running" return self.name class RunningState(State): def on_enter(self): print("进入运行状态") def on_exit(self): print("退出运行状态") def handle_event(self, event): if event == "stop": print("停止任务") return "idle" return self.name # 创建状态机并设置初始状态为IdleState state_machine = StateMachine(IdleState()) # 处理事件 state_machine.handle_event("start") # 输出: 进入空闲状态 # 开始任务 state_machine.transition_to(RunningState()) # 输出: 退出空闲状态 # 进入运行状态 state_machine.handle_event("stop") # 输出: 停止任务 # 退出运行状态 # 进入空闲状态 ``` 以上示例代码展示了一个简单的状态机,其中包括两个状态,即"空闲"和"运行"。状态之间的切换由事件触发,例如"start"事件将从"空闲"状态切换到"运行"状态,"stop"事件将从"运行"状态切换回"空闲"状态。每个状态都有进入(on_enter)和退出(on_exit)方法,在切换到新状态时会调用这些方法。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值