之前通过《状态模式》介绍了一下状态模式的使用,这次我们来介绍一下有限状态机
维基百科中是这样定义的:有限状态机(FSM)又称有限状态自动机(FSA),简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学计算模型,在任何给定时间都可以恰好处于有限数量的状态之一
其实状态模式也可以算是状态机的一种实现,除了状态模式,还有一种实现方式就是创建一个描绘迁移的数据表,该表被一个处理事件的处理引擎解释。引擎查找与事件匹配的迁移,调用响应的动作并更改状态,这样状态机的逻辑全部集中在了一个地方
所以表驱动的状态机和状态模式的主要区别就是:状态模式对于状态相关的行为进行建模,而表驱动的方法着重于定义状态转换
这里我们介绍一下表驱动的状态机实现,虽然这方式叫基于表驱动的状态机,但是这个表不是说特指我们平时用的数据库的表,而是一种关系的记录
现在已经有了很多成熟开源的状态机可以使用,如 Spring Statemachine、Squirrel Statemachine和stateless4j,平时工作如果需要,直接使用就好而不需要自己再开发,这次就以最轻量级的 stateless4j 为例来介绍一下状态机的使用
还是使用《敏捷软件开发:原则、模式与实践(C#版)》中的闸机例子

具体代码如下
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 
 | 
 
 
 
 
 StateMachineConfig<State, Trigger> phoneCallConfig = new StateMachineConfig<>();
 
 
 phoneCallConfig.configure(State.LOCKED)
 
 .permit(Trigger.COIN, State.UNLOCKED, () -> {
 System.out.println("opening...");
 })
 
 .permitInternal(Trigger.PASS, () -> {
 
 System.out.println("alarming...");
 });
 
 phoneCallConfig.configure(State.UNLOCKED)
 
 .permit(Trigger.PASS, State.LOCKED, () -> {
 System.out.println("locking...");
 })
 
 .permitInternal(Trigger.COIN, () -> {
 
 System.out.println("thank you...");
 });
 
 StateMachine<State, Trigger> turnStileSm =
 new StateMachine<>(State.LOCKED, phoneCallConfig);
 
 
 turnStileSm.fire(Trigger.COIN);
 Assert.assertEquals(State.UNLOCKED, turnStileSm.getState());
 
 
 turnStileSm.fire(Trigger.COIN);
 Assert.assertEquals(State.UNLOCKED, turnStileSm.getState());
 
 
 turnStileSm.fire(Trigger.PASS);
 Assert.assertEquals(State.LOCKED, turnStileSm.getState());
 
 
 turnStileSm.fire(Trigger.PASS);
 Assert.assertEquals(State.LOCKED, turnStileSm.getState());
 
 | 
当然,这里只是展示了一下简单的用法,具体有兴趣的可以去了解一下对应状态机提供的API
状态机可以应用的地方还有很多,如
- TCP协议中,在连接的不同状态(建立连接、监听中、关闭),对于发送等行为处理逻辑不同
- 一些画图类工具,用户选择了如画矩形、画圆形等按钮,则触发状态转换,此时拖动数据会触发画图的不同画圆或者画矩形等行为
- 用户界面,对于哪些按钮是激活态,哪些按钮置灰不可用,则可以通过状态来进行控制,不同状态下的展示效果不同
参考资料
- 《设计模式-可复用面向对象软件的基础》
- 《敏捷软件开发:原则、模式与实践(C#版)》