有限状态机问题编程实践(上)

简介: 摘要:一般来说,实体的可能状态是有限的, 在满足一定的条件的情况下触发特定动作会发生实体的状态迁移。对于这类问题,我们一般称为FSM(Finite State Machine), 即有限状态机。本文分享一个有限状态机的java实现,以及使用DSL实现的通用化描述。

在日常开发工作中, 我们在建模时会经常遇到实体在多个状态间进行变迁的问题, 比如:

一个订单的状态可能是 “已下单” , “已支付”, “取消”, “完成” 等,并且在满足一定的条件的情况下触发特定动作会发生实体的状态迁移。一般来说,实体的可能状态是有限的, 对于这类问题,我们一般称为FSM(Finite State Machine), 即有限状态机。举个以前项目的例子:


某种设备通过GPRS连接到控制中心, 并且通过接受控制中心的控制指令来改变自身的运行状态,为了达到这个目的, 设备的底层系统提供了控制设备的API:


image.png




现在要求上层编写设备管理程序, 其状态图如下:


image.png


这是一个典型的状态机实现的问题, 设备拥有多个可能的状态, 并且在特定状态下接受正确的指令后可以迁移到指令的目标状态,直观的看,状态机是一个有向图,状态为端点,操作为边, 一个状态端点在特定操作的驱动下迁移到另一个状态端点。


一份快速的实现

我们用伪代码来描述如下:

define state = shutdown;

do function start();

set state = started;

done;

同时,一个完整的状态变迁图告诉我们如下事实:

  • 一个状态端点可以由哪些状态端点变迁而来
  • 一个状态端点可以变迁到哪些状态端点而去

那么针对这个问题我们可以快速的给出如下的一份实现:

//获取接受到的命令类型

final EventTypeEnum eventType = event.eventType();

//获取接受到的命令内容

final byte[] cmd = event.getInstruction();

switch (eventType) {

//接收到设备启动指令

case BOOT:

switch (currentDeviceStatus) {

//当前状态为关闭状态, 允许启动

case STATUS_POWEROFF:

//获取设备底层API并调用

DeviceRuntime.getDevice().boot(cmd);

currentDeviceStatus =

DeviceStatus.STATUS_BOOTED;

return true;

default:

return false;

}

//接受到设备关闭指令

case POWEROFF:

switch (currentDeviceStatus) {

//当前设备状态为已配置, 允许执行

case STATUS_CONFIURED:

//当前设备状态为已启动, 允许执行

case STATUS_BOOTED:

//当前设备状态为已待机, 允许执行

case STATUS_STANDBY:

//当前设备状态为在网待机,允许执行

case STATUS_LINKED_STANDBY:

DeviceRuntime.getDevice().shutdown(cmd);

currentDeviceStatus =

DeviceStatus.STATUS_POWEROFF;

return true;

default:

return false;

}

//接收到设备激活指令

case ACTIVE:

//...

case CONFIGURE:

//...

case LINK:

//...

case OFFLINE:

//...

case STANDBY:

//...

default:

return false;

我们用2层的switch来约束特定源状态,特定操作,特定目标状态, 如果不考虑状态机的修改,这应该是一个不错的实现,正确,简洁,易读. 但是在应付变化这方面就显得比较无能为力, 原因在于,这个版本的实现缺少结构化的抽象,缺乏职责划分导致无法做到变化的隔离。

考虑一下, 如果我们新增加一个状态, 按照当前的实现, 我们需要做的事情是这样的:

  • 了解新端点是那些边的目标端点
  • 在外层switch中为每条指向新端点的边构造一个switch分支,在内层switch中为每
  • 个源端点构建一个状态变迁实现
  • 了解新增端点是那些原有端点的源
  • 在外层switch中为每条指向原有端点的边构造一个switch分支,在每个内层switch中为新增端点建立一个状态变迁实现


改进后的实现

很明显,正确的完成这件事情并不容易,试想如果一个状态机包含几十个状态,上百个动作,一次要新增或删除数个节点,改动和测试的复杂度将非常高。

下面我们来改进上面的实现, 前面讲过, 一个状态端点在特定操作的驱动下迁移到另一个状态端点, 这是状态机的唯一行为模式,是稳定的, 不稳定的是新增状态时的前置约束,指令的新增以及状态的变化, 所以从大体上我们需要把稳定的行为和不稳定的行为进行隔离和抽象。

首先, 我们再来对一次状态变迁进行分析:



image.png


一次状态迁移必然包含如下要素:

  • 迁移的事件类型是什么? 比如启动, 激活, 关闭等
  • 迁移的原状态时什么? 比如 启动类型的迁移, 其原状态必须是已关闭
  • 迁移结束后的状态是什么? 比如 启动类型的迁移, 其目标状态时已启动
  • 迁移指令如何执行

如果我们从这个角度来进行抽象, 我们需要一个操作模型来封闭起始状态和指令的执行,那么我们首先来定义一个设备的操作:

public interface DeviceOperation {

/**

* 返回此操作代表的类型

* @return 操作代表的类型

*/

public EventTypeEnum operationType();

/**

* 声明设备在什么状态下允许执行此操作

* @return 操作可执行的设备状态

*/

public Set<DeviceStatus> avaliableStatus();

/**

* 声明如果此指令操作成功, 设备应该处于的下一个状态

* @return 设备的新状态

*/

public DeviceStatus nextStatus();

/**

* 执行指令操作

* @param cmd 指令数据

*/

public void doOperation(final byte[] cmd);

}

一个操作(边)有它自己的类型, 有执行指令的实现,有目标端点和源端点。所有的要素都有了, 我们可以这样描述一个具体实现

操作X -> "操作X的类型为 operationType() , 在当前状态为 avaliableStatus()之一时允许执行指令操作doOperation(#cmd#), 成功执行后设备状态更改为nextStatus()"

由于指令模型再执行指令时向上表现为一致的行为方式, 而底层设备为不同指令提供了不同的API, 因此在真正执行指令操作的地方, 我们也需要进行抽象和适配(下图仅列出部分操作):


image.png



相关文章
|
6月前
|
Python
电学:原理、应用与编程实践
电学:原理、应用与编程实践
|
6月前
|
Python
物理光学初探:原理、应用与编程实践
物理光学初探:原理、应用与编程实践
|
11月前
|
人工智能 安全 图形学
有限状态机的概念
有限状态机的概念
154 0
|
C语言 Perl
西门子S7-1200有哪几种编程方法?什么是线性化编程、模块化编程、结构化编程?
今天我们来说一说西门子S7-1200有哪几种编程方法,给大家简单介绍一下什么是线性化编程、模块化编程和结构化编程。
西门子S7-1200有哪几种编程方法?什么是线性化编程、模块化编程、结构化编程?
有限状态机
有限状态机简介 有限状态机(FSM)是许多数字系统中用来控制系统和数据流路径行为的时序电路。FSM的实例包括控制单元和时序。 本实验介绍了两种类型的FSM(Mealy和Moore)的概念,以及开发此类状态机的建模方式。 请参阅Vivado教程,了解如何使用Vivado工具创建项目和验证数字电路。 Mealy FSM(米利型有限状态机) 有限状态机(FSM)或称简单状态机用于设计计算机程序和时序逻辑电路。它被设想为抽象机器,可以处于有限数量的用户定义状态之一。机器一次只能处于一种状态; 它在任何给定时间所处的状态称为当前状态。 当由触发事件或条件启动时,它可以从一种状态改变为另一种状态;
214 0
|
消息中间件 安全 程序员
关于防御性编程,你应该知道的事
提起编程,对于程序员同学而言并不陌生,关于防御性编程相信大家也有所耳闻,但是它具体包括哪些内容呢?
关于防御性编程,你应该知道的事
|
XML 设计模式 数据可视化
有限状态机问题编程实践(下)
有限状态机问题编程实践(下)
205 0
|
API Python
transitions-一种轻量级的,面向对象的有限状态机实现
transitions是Python中的轻量级、面向对象的状态机实现,具有许多扩展。与Python 2.7+和3.0+兼容。 任何好的状态机(毫无疑问,还有很多坏的状态机)的灵魂都是一组状态。我们通过将字符串列表传递给Machine初始化程序来定义有效的模型状态。但是在内部,状态实际上表示为State对象。
1620 0
transitions-一种轻量级的,面向对象的有限状态机实现
|
调度
状态机思路在程序设计中的应用(转)
  状态机的概念   状态机是软件编程中的一个重要概念,比这个概念更重要的是对它的灵活应用。在一个思路清晰而且高效的程序中,必然有状态机的身影浮现。   比如说一个按键命令解析程序,就可以被看做状态机:本来在A状态下,触发一个按键后切换到了B状态,再触发另一个键后切换到C状态,或者返回到A状态。
1779 0
下一篇
无影云桌面