有限状态机是一种用来进行对象行为建模的工具

必威 1有限状态机

Atitit. 有限状态机 fsm 状态模式

  • Async和Await异步编程的原理

有限状态机(finite state machine)简称FSM,表示有限个状态及在这些状态之间的转移和动作等行为的数学模型,在计算机领域有着广泛的应用。FSM是一种逻辑单元内部的一种高效编程方法,在服务器编程中,服务器可以根据不同状态或者消息类型进行相应的处理逻辑,使得程序逻辑清晰易懂。

『代码github地址』

有限状态机是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。在计算机科学中,有限状态机被广泛用于建模应用行为、硬件电路系统设计、软件工程,编译器、网络协议、和计算与语言的研究。比如下图非常有名的TCP协议状态机。

 

在上面的这个简单状态机中,调用者不需要知道状态机下一步要干什么,它只被告知在某个时候需要调用MoveNext,具体干什么由状态机的内部实现决定。

那有限状态机通常在什么地方被用到?

标签: 有限状态机,Akka fsm,squirrel-foundation,java状态模式、责任链模式

必威 2

1. 有限状态机 1

  • 技术系列之“状态机”

处理程序语言或者自然语言的 tokenizer,自底向上解析语法的parser,
各种通信协议发送方和接受方传递数据对消息处理,游戏AI等都有应用场景。


其实我们在编程时实现相关业务逻辑时经常需要处理各种事件和状态切换,写各种switch/case 和if/else ,所以我们其实可能一直都在跟有限状态机打交道,只是可能没有意识到。在处理一些业务逻辑比较复杂的需求时,可以先看看是否适合用一个有限状态机来描述,如果可以把业务模型抽象成一个有限状态机,那么代码就会逻辑特别清晰,结构特别规整。

2. “状态表”和“状态轮换表” 1

与编译原理中的状态机不同,软件设计领域中通用状态机的输入不是字符集,而是被称作事件的结构(可以是结构体,也可以是类对象),并且特定的状态下,针对发生的事件,不仅发生状态改变,而且产生动作。

状态机有以下几种实现方法,我将一一阐述它们的优缺点。

1. 有限状态机的概念

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

通常FSM包含几个要素:状态的管理、状态的监控、状态的触发、状态触发后引发的动作。

这些关系的意思可以这样理解:

  • State(S) x Event(E) -> Actions (A), State(S’)
  • 如果我们当前处于状态S,发生了E事件, 我们应执行操作A,然后将状态转换为S’

下面展示最常见的表示:当前状态(B)和条件(Y)的组合指示出下一个状态(C)。完整的动作信息可以只使用脚注来增加。包括完整动作信息的FSM定义可以使用状态表。

条件↓当前状态→ 状态A 状态B 状态C
条件X
条件Y 状态C
条件Z

下面我们就来聊聊所谓的状态机,以及它如何在代码中实现。

3. 有限状态机概念(状态(State)事件(Event)转换(Transition) 动作(Action) 2

  • 状态机思路在程序设计中的应用

一、使用if/else if语句实现的FSM 使用if/else if语句是实现的FSM最简单最易懂的方法,我们只需要通过大量的if /else if语句来判断状态值来执行相应的逻辑处理。

2. 使用状态机的应用背景

在广告投放项目中由于复杂的广告投放逻辑,存在着大量的if-else 判断类似的硬编码,希望能借助对fsm模型的调研,找出理想的实现方式。

1、状态机的要素

4. 状态机的应用场景 2

状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果关系的考虑。“现态”和“条件”是因,“动作”和“次态”是果。详解如下:

①现态:是指当前所处的状态。

②条件:又称为“事件”。当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。

③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。

④次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。

。。。

初学者往往会把某个“程序动作”当作是一种“状态”来处理,我称之为“伪态”。那么如何区分“动作”和“状态”?本匠人的心得是看二者的本质:“动作”是不稳定的,即使没有条件的触发,“动作”一旦执行完毕就结束了;而“状态”是相对稳定的,如果没有外部条件的触发,一个状态会一直持续下去。

看看下面的例子,我们使用了大量的if/else if语句实现了一个简单的状态机,做到了根据状态的不同执行相应的操作,并且实现了状态的跳转。

3.有限状态机的几种实现

状态机可归纳为4个要素,即现态、条件、动作、次态。“现态”和“条件”是因,“动作”和“次态”是果。详解如下:

4.1. ,“有限状态机”在游戏的人工智能方面是很有用处的。 2

  • 状态机的两种写法
//比如我们定义了小明一天的状态如下
enum
{
  GET_UP,
  GO_TO_SCHOOL,
  HAVE_LUNCH,
  GO_HOME,
  DO_HOMEWORK,
  SLEEP,
};


int main()
{
  int state = GET_UP;
  //小明的一天
  while (1)
  {
    if (state == GET_UP)
    {
      GetUp(); //具体调用的函数
      state = GO_TO_SCHOOL; //状态的转移
    }
    else if (state == GO_TO_SCHOOL)
    {
      Go2School();
      state = HAVE_LUNCH;
    }
    else if (state == HAVE_LUNCH)
    {
      HaveLunch();
    }
    ...
    else if (state == SLEEP)
    {
      Go2Bed();
      state = GET_UP;
    }
  }

  return 0;
}

3.1枚举类实现java状态模式

首先在枚举类中 定义state 和定义的抽象方法。

public enum JavaPlatformState {
    //  定义state
    OPEN{
        @Override void exit(JavaPlatformMachine pm){super.exit(pm);}

        @Override void valid(JavaPlatformMachine pm){
            this.exit(pm);
            if(pm.data.getValid_()){
                pm.state =STEP1;
            }else{
                NotFound();
                pm.state =OFF;
            }
            pm.state.entry(pm);
        }

        @Override
        void first(JavaPlatformMachine pm) {}

        @Override
        void businessLine(JavaPlatformMachine pm) {}

        @Override
        void district(JavaPlatformMachine pm) {}
    },
    STEP1{
        @Override void exit(JavaPlatformMachine pm){super.exit(pm);}

        @Override
        void valid(JavaPlatformMachine pm) {}

        @Override void first(JavaPlatformMachine pm){
            this.exit(pm);
            if(!pm.data.getFirst_()){
                pm.state =STEP2;
            }else{
                ReturnDimension();
                pm.state =OFF;
            }
            pm.state.entry(pm);
        }

        @Override
        void businessLine(JavaPlatformMachine pm) {}

        @Override
        void district(JavaPlatformMachine pm) {}
    },
    ...

    //状态模式 提取的接口  在常量实体类中实现抽象方法
    abstract void valid(JavaPlatformMachine pm);
    abstract void first(JavaPlatformMachine pm);
    abstract void businessLine(JavaPlatformMachine pm);
    abstract void district(JavaPlatformMachine pm); 
}      

在enum JavaPlatformState 中,除了状态模式 提取的接口外,添加了状态机的各种动作action实现

//状态机的各种动作action methode
    void entry(JavaPlatformMachine pm){System.out.println("→"+pm.state.name());}
    void exit(JavaPlatformMachine pm){System.out.println(pm.state.name()+"→ ");}

    void NotFound(){System.out.println("NotFound");}
    void ReturnDimension(){System.out.println("ReturnDimension");}
    void PreciseAdvertising(){System.out.println("PreciseAdvertising");}
    void Top9(){System.out.println("Top9");}

建立状态机实体,ContextData是封装条件的bean类,初始化状态OPEN,在状态机里定义action,调用对应state的相应的方法。

public class ContextData {
    private Boolean isValid_;//广告位是否有效
    private Boolean isFirst_;//是否第一次请求
    private Boolean isBusinessLine_;//是否属于业务线广告位
    private Boolean district_;//是否有地域
    ...
}    

public class JavaPlatformMachine {
    ContextData data = new ContextData();
    JavaPlatformState state = JavaPlatformState.OPEN;
    //Action
    public void valid(){state.valid(this);}
    public void first(){state.first(this);}
    public void businessLine(){state.businessLine(this);}
    public void district(){state.district(this);}
}

测试方法,初始化状态机,设置参数,按次序调用对应的Action

    JavaPlatformMachine pm = new JavaPlatformMachine();
    pm.data.setValid_(true);// 广告位是否有效
    pm.data.setFirst_(false);// 是否第一次请求
    pm.data.setBusinessLine_(true);//是否属于业务线广告位
    pm.data.setDistrict_(true);//是否有地域
    pm.valid();
    pm.first();
    pm.businessLine();
    pm.district();

输出结果

OPEN→ 
→STEP1
STEP1→ 
→STEP2
STEP2→ 
→STEP3
STEP3→ 
Top9
→OFF

在设置参数下,最后状态调用Top9。
不过这种方式在枚举类中实现抽象方法,每个state下都要覆写(Override)action的抽象方法,显然不利于拓展。

参考资料:
http://blog.csdn.net/yqj2065/article/details/39371487

①现态:是指当前所处的状态。

4.2. 用状态机模式消除复杂的 if else 逻辑 2

有限状态机FSM思想广泛应用于硬件控制电路设计,也是软件上常用的一种处理方法(软件上称为FMM有限消息机)。它把复杂的控制逻辑分解成有限个稳定状态,在每个状态上判断事件,变连续处理为离散数字处理,符合计算机的工作特点。

看完上面的例子,大家有什么感受?是不是感觉程序虽然简单易懂,但是使用了大量的if判断语句,使得代码很低端,同时代码膨胀的比较厉害。这个状态机的状态仅有几个,代码膨胀并不明显,但是如果我们需要处理的状态有数十个的话,该状态机的代码就不好读了。

3.2抽象类实现java状态模式

当一个类的某个成员变量的值变化时,可能导致多个行为表现得不同。将该成员变量封装成类型的模式,即为状态模式(state pattern)。即用多态来重构分支结构。

首先抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为

public abstract class State {
    public abstract void Handle(StateModeContext context );
    public abstract boolean isFinalflag();
}

Context类,维护一个State子类的实例,这个实例定义当前的状态。

public class StateModeContext
{
    private State state;
    private ContextData data ;

    public ContextData getData() {
        return data;
    }

    public void setData(ContextData data) {
        this.data = data;
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    /// 定义Context的初始状态
    public StateModeContext(State state , ContextData data )
    {
        this.data = data;
        this.state = state;
    }

    /// 对请求做处理,并设置下一个状态
    boolean  trueFlag = true;

    public void Request()
    {
        //如果当前step 是最后一步  nextStep 不执行
        if(state.isFinalflag()){
            trueFlag = false;
        }
        state.Handle(this);
    }
}

最后定义各个状态子类

public class State404 extends State {
    @Override
    public void Handle(StateModeContext context) {
        System.out.println("当前状态是 404  do something");
    }
    @Override
    public boolean isFinalflag() {
        return true;
    }
}

其中设置一个FinalFlag 标识 是否是最终状态。
在下面state的子类里面进行条件判断,并设置下一个状态,这一点有点类似责任链模式(在抽象类中定义一个实例成员变量 next handler 的引用)

public class StateStep1 extends State {
    @Override
    public void Handle(StateModeContext context) {
        System.out.println("当前状态是 step1");
        ContextData data = context.getData();
        if(data.getFirst_()){
            System.out.println("step1 -> dimension(返回尺寸)");
            context.setState(new StateDimension());
        }else{
            System.out.println("step1 -> step2");
            context.setState(new StateStep2());
        }
    }
    @Override
    public boolean isFinalflag() {
        return false;
    }
}

测试类:设置初始化数据和初始化状态stateOpen,根据状态树的深度确定循环迭代次数,进行迭代。

public class StateModeTest {
    public static void main(String[] args) {
        // 设置Context的初始状态为ConcreteStateA
        ContextData data = new ContextData(true,false,true,true);
        StateModeContext context = new StateModeContext(new StateOpen(),data);
        // 不断地进行请求,同时更改状态
        int size = 4;// 请求迭代数
        for(int i = 0 ; i< size+1; i++){
            if(context.trueFlag){
                context.Request();
            }
        }
    }
}

输出结果:

当前状态是 open
open -> step1
当前状态是 step1
step1 -> step2
当前状态是 step2
step2 -> step3
当前状态是 step3
step3 -> Top9(返回9素材)
当前状态是 Top9(返回9素材)  do something

这种方式实现状态模式,每个状态要new一个状态的子类,而且手动指定循环迭代次数通过迭代方式进行事件的调用。

②条件:又称为“事件”。当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。

4.3. 源码文本处理状态机 2

 

二、使用switch实现FSM

3.3 Akka FSM 实现状态机

Akka的状态机是非常简洁的实现,充分利用了Scala的许多先进的语法糖让代码更加简洁清晰。是基于Akka Actor 实现,封装了很多自定义的API(实际上就是DSL)。

在底层,Akka FSM就是一个继承了Actor的trait(scala的特征trait就相当于java的接口)

trait FSM[S, D] extends Actor with Listeners with ActorLogging { ...}

FSM trait提供了一个包装了常规Actor的DSL,让我们能集中注意力在更快的构建手头的状态机上。常规Actor只有一个receive方法,FSM trait包装了receive方法的实现并将调用指向到一个特定状态机的处理代码块。

class PlatformMachine extends FSM[PlatformState,PlatformData]

上面的 PlatformMachine 是一个FSM ACTOR。
PlatformState,PlatformData分别为我定义的状态和数据。在FSM中,有两个东西是一直存在的,任何时间点都有状态 ,和在状态中进行共享的数据。 这代表所有的fsm的状态继承自PlatformState,而所有在状态间共享的数据就是PlatformData

在伴生对象中定义状态,消息,数据。

在Scala的类中,与类名相同的对象(object)叫做伴生对象,类和伴生对象之间可以相互访问私有的方法和属性。在Scala中没有静态方法和静态字段,但是可以使用object这个语法结构来达到同样的目的。object是单例模式的,一般也用于存放工具方法和常量,共享单个不可变的实例等。

在Scala中样例类(case class)是一中特殊的类,可用于模式匹配。case class是多例的,后面要跟构造参数,case object是单例的。这点其实和class与object的区别是一样的。

object PlatformMachine{
  sealed trait PlatformState
  //定义6个State
  case object Open extends PlatformState
  case object Off extends PlatformState
  case object Step1 extends PlatformState
  case object Step2 extends PlatformState
  case object Step3 extends PlatformState
  case object Step4 extends PlatformState
  // state data container
  case class PlatformData(isValid: Boolean, isFirst: Boolean, isBusinessLine: Boolean,district:Boolean)
  //定义交互消息
  sealed trait UserMessage
  case object ToHoldOn extends  UserMessage
  case object ToNotFound extends  UserMessage
  case object ToReturnDimension extends UserMessage
  case object ToPreciseAdvertising extends UserMessage
  case object ToTop9 extends UserMessage
  case class SetInitData(isValid: Boolean, isFirst: Boolean, isBusinessLine: Boolean,district:Boolean) extends UserMessage
}

以下是FSM 类的代码

class PlatformMachine extends FSM[PlatformState,PlatformData]{
  val service = new PlatformMachineService()

  startWith(Open, PlatformData(false,false,false,false))

  //Handlers of State
  when(Open){
    case Event(SetInitData(isValid_,isFirst_,isBusinessLine_,district_), _) =>{
      println(s"SetInitData:$isValid_ , $isFirst_ ,$isBusinessLine_ ,$district_  ")
      stay using stateData.copy(isValid = isValid_,isFirst=isFirst_,isBusinessLine=isBusinessLine_,district=district_)
    }

    case Event(ToNotFound, PlatformData(isValid,_,_,_))   => {
      if (isValid equals  false)  {
        println("goto NotFound!")
        service.notFound()
        goto(Off)
      }else{
        println("goto step1")
        goto(Step1)
      }
    }
  }

  when(Off){
    //接收off状态下的所有Event
    case _ => {
      println("end !")
      stay()
    }
  }

  when(Step1){
    case Event(ToReturnDimension, PlatformData(_,isFirst,_,_))   => {
      //是否第一次请求 /是  返回广告位大小尺寸数据
      if (isFirst equals  true){
        println("goto ReturnDimension!")
        service.returnDimension()
        goto(Off)
      }else{
        println("goto step2")
        goto(Step2)
      }
    }
  }

  when(Step2){
    case Event(ToPreciseAdvertising, PlatformData(_,_,isBusinessLine,_))   => {
      //是否业务线广告位 /是  返回精准投放
      if (isBusinessLine equals  false){
        println("goto PreciseAdvertising!")
        service.preciseAdvertising()
        goto(Off)
      }else{
        println("goto step3")
        goto(Step3)
      }
    }
  }

  when(Step3){
    case Event(ToTop9, PlatformData(_,_,_,district))   => {
      //是否有地域 /是  返回9素材
      if (district equals  true){
        println("goto Top9!")
        service.top9()
        goto(Off)
      }else{
        println("goto step4")
        goto(Step4)
      }
    }
  }

  when(Step4){
    //接收off状态下的所有Event
    case _ => {
      println("Step4 end !")
      stay()
    }
  }

  whenUnhandled {
    case _ => {
      goto(Open)
    }
  }

  onTransition {
    case Open  -> Step1 => println("-------------------------onTransition : from Open to Step1  ! ")
    case Open  -> Off   => println("-------------------------onTransition : from Open to OFF    ! ")
    case Step1 -> Step2 => println("-------------------------onTransition : from Step1 to Step2 ! ")
    case Step1 -> Off   => println("-------------------------onTransition : from Step1 to OFF   ! ")
    case Step2 -> Step3 => println("-------------------------onTransition : from Step2 to Step3 ! ")
    case Step2 -> Off   => println("-------------------------onTransition : from Step2 to OFF   ! ")
    case Step3 -> Step4 => println("-------------------------onTransition : from Step3 to Step4 ! ")
    case Step3 -> Off   => println("-------------------------onTransition : from Step3 to OFF   ! ")
  }

}

如上,首先是定义初始化状态为open和初始化数据。

startWith(Open, PlatformData(false,false,false,false))

接下来是状态处理器,根据各个业务来,例如:

when(Open){
    case Event(SetInitData(isValid_,isFirst_,isBusinessLine_,district_), _) =>{
      println(s"SetInitData:$isValid_ , $isFirst_ ,$isBusinessLine_ ,$district_  ")
      stay using stateData.copy(isValid = isValid_,isFirst=isFirst_,isBusinessLine=isBusinessLine_,district=district_)
    }

    case Event(ToNotFound, PlatformData(isValid,_,_,_))   => {
      if (isValid equals  false)  {
        println("goto NotFound!")
        service.notFound()
        goto(Off)
      }else{
        println("goto step1")
        goto(Step1)
      }
    }
  }

我们有一个初始状态(Open),when(open)代码块处理Open状态的
收到的消息event,ToNotFound由when(ToNotFound)代码块来处理。我提到的消息与常规我们发给Actor的消息时一样的,消息与数据一起包装过。包装后的叫做Event(akka.actor.FSM.Event),看起来的样例是这样case Event(ToNotFound, PlatformData(isValid,_,_,_)),比如我这里获得了isValid的参数,在Open的状态下模式匹配到了ToNotFound,在函数里面根据参数做业务判断,调用业务方法或者通过调用goto方法,调度到下一个状态。

还有一个event是SetInitData,我这里是设置自定义初始化数据用的,其中有几个关键字stay,usingstateData

每一个被阻塞的case都必须返回一个State。这个可以用stay来完成,含义是已经在处理这条消息的最后了,以下是stay方法的源码实现:

 final def stay(): State = goto(currentState.stateName) // cannot directly use currentState because of the timeout field

其实也就是调用了goto
using方法可以让我们把改过的数据传给下个状态。

  whenUnhandled {
    case _ => {
      goto(Open)
    }
  }

  onTransition {
    case Open  -> Step1 => println("-------------------------onTransition : from Open to Step1  ! ")
    case Open  -> Off   => println("-------------------------onTransition : from Open to OFF    ! ")
    case Step1 -> Step2 => println("-------------------------onTransition : from Step1 to Step2 ! ")
    case Step1 -> Off   => println("-------------------------onTransition : from Step1 to OFF   ! ")
    case Step2 -> Step3 => println("-------------------------onTransition : from Step2 to Step3 ! ")
    case Step2 -> Off   => println("-------------------------onTransition : from Step2 to OFF   ! ")
    case Step3 -> Step4 => println("-------------------------onTransition : from Step3 to Step4 ! ")
    case Step3 -> Off   => println("-------------------------onTransition : from Step3 to OFF   ! ")
  }

whenUnhandled 是如果没有匹配到,FSM Actor会尝试将我们的消息与whenUnhandled块中的模式进行匹配。
onTransition 是在状态变化时做出反应或得到通知。
测试类:

class PlatformSpec extends TestKit(ActorSystem("platform-system"))
  with MustMatchers  //must描述assertion,比如"hello" must (contain("hello"))
  with FunSpecLike
  with ImplicitSender {
  val begin: Long = System.currentTimeMillis()
  describe("just 4 test") {
    it("TestKit Demo") {
      val platformMachine = TestActorRef(Props(new PlatformMachine()))
      platformMachine ! SetInitData(true,false,false,true)
      platformMachine ! ToNotFound
      platformMachine ! ToReturnDimension
      platformMachine ! ToPreciseAdvertising
      platformMachine ! ToTop9
    }
  }
  val end: Long = System.currentTimeMillis()
  System.out.println("方法耗时:"+(end-begin));
}

new 一个状态机,对这个ActorRef 发送消息,按顺序执行。这里的和scala Actor 编程的模式一样,表示发送异步消息,没有返回值。
执行结果:

方法耗时:36
SetInitData:true , false ,false ,true  
goto step1
-------------------------onTransition : from Open to Step1  ! 
goto step2
-------------------------onTransition : from Step1 to Step2 ! 
goto PreciseAdvertising!
精准投放!
-------------------------onTransition : from Step2 to OFF   ! 
end !

由结果看出来,其也是异步调用的。
由于网上找的资料都是用继承Akka的TestKit测试包来进行测试的demo,现在我还没找到实际能用于生产上的解决方案。
如我下面代码:

object PlatformTest extends App{
  private val begin: Long = System.currentTimeMillis()
  val system = ActorSystem()
  val machine: ActorRef = system.actorOf(Props[PlatformMachine],"plantformTest")
  machine ! SetInitData(true,false,true,true)
  machine ! ToNotFound
  machine ! ToReturnDimension
  machine ! ToPreciseAdvertising
  machine ! ToTop9
  Thread.sleep(100)
  system.shutdown()
  private val end: Long = System.currentTimeMillis()
  System.out.println("方法耗时:"+(end-begin));
//  system.awaitTermination()
}

其测试结果:

SetInitData:true , false ,true ,true  
goto step1
-------------------------onTransition : from Open to Step1  ! 
goto step2
-------------------------onTransition : from Step1 to Step2 ! 
goto step3
-------------------------onTransition : from Step2 to Step3 ! 
goto Top9!
返回9素材!
-------------------------onTransition : from Step3 to OFF   ! 
方法耗时:638

通过ActorSystem调用actorOf的方式 获得machine这个ActorRef,进行异步发送消息,我这里是先线程sleep 再关闭ActorSystem。这块我用的比较浅,还没有找到其他更好的方法。

参考资料:
http://udn.yyuap.com/doc/akka-doc-cn/2.3.6/scala/book/chapter3/07_fsm.html
http://www.jianshu.com/p/41905206b3b3
http://www.cnphp6.com/archives/29029

③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。

4.4. 正则表达式(regexp),判断字符串格式和解析字符串内容基本全靠她。 3

使用switch语句实现的FSM的结构变得更为清晰了,其缺点也是明显的:这种设计方法虽然简单,通过一大堆判断来处理,适合小规模的状态切换流程,但如果规模扩大难以扩展和维护。

3.4 squirrel state machine 实现状态机

squirrel-foundation是一款轻量级的java有限状态机。既支持流式API又支持声明式创建状态机,允许用户以一种简单方式定义操作方法。这里只介绍状态机squirrel的初级用法。

本文由必威发布于必威-编程,转载请注明出处:有限状态机是一种用来进行对象行为建模的工具

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。