【保姆级】一篇入门Squirrel-Foundation状态机

1,089 阅读3分钟

放在前面的一些介绍🤖

这部分了解的朋友可以跳过,直接上手后面的代码( ̄∇ ̄)/

Squirrel-Foundation 🆚 StatusMachine

Squirrel-Foundation和StatusMachine都是Java状态机框架,用于实现状态机模式,它们的主要区别有以下4点:

  1. 语法和API

    1.   Squirrel-Foundation使用类似于DSL的语法和函数式API,而StatusMachine使用基于注解的方式来定义状态和转换,两者在语法和API上有较大的差异。

    2. DSL

      •     DSL的全称是“Domain Specific Language”,即领域特定语言。它是一种用于特定领域的编程语言,通常具有更加简单、清晰和易于理解的语法和API,能够提高代码的可读性和可维护性。DSL的语法和API通常会针对具体的问题领域进行优化,以便更加贴合领域的需求。
    3. 函数式API

      •     函数式API是一种编程范式,它将函数作为一等公民,允许将函数作为参数传递、返回值或者赋值给变量,从而实现代码的复用和组合。函数式API通常具有不可变性、高阶函数、Lambda表达式等特性,能够提高代码的可读性、可维护性和性能。

在Java中,DSL的语法和函数式API通常用于实现流畅接口(Fluent Interface)和方法链式调用(Method Chaining),以提高代码的简洁性和可读性。

  1. 功能

    1.   Squirrel-Foundation提供了更加丰富的功能,如状态机持久化、异步事件处理、状态机层次结构等,而StatusMachine则更加注重简单易用,功能相对较少。
  2. 兼容性

    1. Squirrel-Foundation支持JDK 1.6及以上版本,可以在Java SE和Android应用中使用
    2. StatusMachine仅支持JDK 1.8及以上版本,不能在低版本的Java应用中使用。
  3. 社区支持

    1.   相比StatusMachine来说,Squirrel-Foundation的社区更为活跃,有广泛的文档和教程可供参考

保姆级Demo

作为一个☝️保姆级博文选手,附上完整可执行的代码是一项基本素质

  1. 添加依赖🌵

<!--   状态机     -->
<dependency>
    <groupId>org.squirrelframework</groupId>
    <artifactId>squirrel-foundation</artifactId>
    <version>0.3.8</version>
    <!-- 可能会出现冲突的jar,如果项目中没有引入一下几类可忽略<exclusions>的部分-->
    <exclusions>
        <exclusion>
            <artifactId>log4j</artifactId>
            <groupId>log4j</groupId>
        </exclusion>
        <exclusion>
            <artifactId>slf4j-log4j12</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>
        <exclusion>
            <artifactId>guava</artifactId>
            <groupId>com.google.guava</groupId>
        </exclusion>
    </exclusions>
</dependency>
  1. 示例代码

下面这段代码是从官网的QuickStartSample改的(嘿嘿类名都没变(˶‾᷄ ⁻̫ ‾᷅˵))


public class QuickStartSample {
    enum TrafficLightEvent {
        GREEN_TO_YELLOW, YELLOW_TO_RED, RED_TO_GREEN, REPAIRED
    }

    enum TrafficLightState {
        GREEN, YELLOW, RED, OFF
    }

    @StateMachineParameters(stateType = TrafficLightState.class, eventType = TrafficLightEvent.class, contextType = Void.class)
    static class TrafficLightMachine extends AbstractUntypedStateMachine {
        /***
         * the method be invoke when status changes
         * @param from
         * @param to
         * @param event
         * @param context
         */
        protected void changeFromGreenToYellow(TrafficLightState from, TrafficLightState to, TrafficLightEvent event, Void context) {
            System.out.println("Traffic light changed from " + from + " to " + to);
        }

        protected void changeFromYellowToRed(TrafficLightState from, TrafficLightState to, TrafficLightEvent event, Void context) {
            System.out.println("Traffic light changed from " + from + " to " + to);
        }

        protected void changeFromRedToGreen(TrafficLightState from, TrafficLightState to, TrafficLightEvent event, Void context) {
            System.out.println("Traffic light changed from " + from + " to " + to);
        }

        protected void repair(TrafficLightState from, TrafficLightState to, TrafficLightEvent event, Void context) {
            System.out.println("Traffic light needs repaired!");
        }

    }

    public static void main(String[] args) {
        UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(TrafficLightMachine.class);
        builder.externalTransition().from(TrafficLightState.GREEN).to(TrafficLightState.YELLOW).on(TrafficLightEvent.GREEN_TO_YELLOW).callMethod("changeFromGreenToYellow");
        builder.externalTransition().from(TrafficLightState.YELLOW).to(TrafficLightState.RED).on(TrafficLightEvent.YELLOW_TO_RED).callMethod("changeFromYellowToRed");
        builder.externalTransition().from(TrafficLightState.RED).to(TrafficLightState.GREEN).on(TrafficLightEvent.RED_TO_GREEN).callMethod("changeFromRedToGreen");
        builder.externalTransition().from(TrafficLightState.RED).to(TrafficLightState.OFF).on(TrafficLightEvent.REPAIRED).callMethod("repair");
        builder.onEntry(TrafficLightState.OFF).callMethod("repair");

        UntypedStateMachine myStateMachine = builder.newStateMachine(TrafficLightState.GREEN);
        myStateMachine.start();
        myStateMachine.fire(TrafficLightEvent.GREEN_TO_YELLOW);
        myStateMachine.fire(TrafficLightEvent.YELLOW_TO_RED);
        myStateMachine.fire(TrafficLightEvent.RED_TO_GREEN);
        myStateMachine.fire(TrafficLightEvent.REPAIRED);
        System.out.println("Current state is " + myStateMachine.getCurrentState());
        myStateMachine.terminate();

    }
}

着急的朋友添加了依赖,直接新建一个同名类(QuickStartSample),把👆上面的代码直接copy进去,就可以看到执行结果叻

补充说明

状态机四要素

QuickStartSample 中体现在如下

@StateMachineParameters(stateType=String.class, eventType=FSMEvent.class, contextType=Integer.class)
static class StateMachineSample extends AbstractStateMachine<MyStateMachine , FSMState , FSMEvent , Integer>

StateMachine接口采用四个泛型类型参数。

StateMachine<T, S, E, C> ,

ps : 要是想看这几个状态的可以向上找下 AbstractStateMachine 关系如下 👇

MyStateMachine extends AbstractUntypedStateMachine

AbstractUntypedStateMachine extends AbstractStateMachine

T-代表已实现状态机的类型 ,, 也就是状态机本体。

S-代表实现状态的类型 。

E-代表已实现事件的类型。

C-代表已实现的外部上下文的类型。

QuickStartSample中体现在如下

StateMachineBuilder<MyStateMachine, MyState, MyEvent, MyContext> builder =
      StateMachineBuilderFactory.create(MyStateMachine.class, MyState.class, MyEvent.class, MyContext.class);      

为了创建状态机,用户需要先创建状态机构建器

本文主要参考官方教程(hekailiang.github.io/squirrel/