什么是状态机?
状态机在我们的程序设计中非常重要,查阅了一些资料写了这篇文章来梳理和复习。
状态机的定义
关于状态机的一个极度确切的描述是:它是一个有向图形,由一组节点和一组相应的转移函数组成。状态机通过响应一系列事件而“运行”。
是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。
每个事件都在属于“当前”
节点的转移函数的控制范围内,其中函数的范围是节点的一个子集。函数返回“下一个”(也许是同一个)节点。这些节点中至少有一个必须是终态。当到达终态,
状态机停止。 包含一组状态集(states)、一个起始状态(start
state)、一组输入符号集(alphabet)、一个映射输入符号和当前状态到下一状态的转换函数(transition
function)的计算模型。当输入符号串,模型随即进入起始状态。它要改变到新的状态,依赖于转换函数。
官方定义 不理解可以往下看。
状态机的分类
状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动作、完成特定操作的控制中心。有限状态机简写为FSM(Finite State Machine),主要分为2大类:
第一类,若输出只和状态有关而与输入无关,则称为Moore状态机
第二类,输出不仅和状态有关而且和输入有关系,则称为Mealy状态机
状态机的应用
程序中有两大类:一类是传统应用程序的控制流程基本是顺序的,主要指控制台程序等“命令行实用程序”。
一类应用程序由外部发生的事件来驱动 ,事件驱动的GUI应用程序是这种应用程序的典型例子,它们由命令和选择(也就是用户造成的事件)来驱动。Web应用程序由提交的表单和用户请求的网页来驱动,它们也可划归到上述类别。
状态机理解&实例
状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果关系的考虑。“现态”和“条件”是因,“动作”和“次态”是果。详解如下:
①现态:是指当前所处的状态。
②条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。
③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
④次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。
状态机就是状态转移图。最简单的例子,人有三个状态:健康,感冒,康复中。触发的条件有淋雨(t1),吃药(t2),打针(t3),休息(t4)。所以状态机就是健康-(t4)->健康;健康-(t1)->感冒;感冒-(t3)->健康;感冒-(t2)->康复中;康复中-(t4)->健康,等等。就是这样状态在不同的条件下跳转到自己或不同状态的图。
设计思路
做需求时,需要了解以下六种元素:起始、终止、现态、次态(目标状态)、动作、条件,我们就可以完成一个状态机图的设计了。起始和终止是特殊的现态和次态
在实际开发中需要用画图工具画出状态机图后再开发
注意事项
1、避免把某个“程序动作”当作是一种“状态”来处理。那么如何区分“动作”和“状态”?“动作”是不稳定的,即使没有条件的触发,“动作”一旦执行完毕就结束了;而“状态”是相对稳定的,如果没有外部条件的触发,一个状态会一直持续下去。
2、状态划分时,必须保证状态的完整性。
代码实现
现在状态机有很多好用的类库,这里推荐github的https://github.com/dotnet-state-machine/stateless state machine
实现最简单的on/off
using System;
using Stateless;
namespace OnOffExample
{
/// <summary>
/// This example has a simple state machine with only two states. The state
/// information is of type string, and the type of the trigger is char.
/// </summary>
class Program
{
static void Main(string[] args)
{
const string on = "On";
const string off = "Off";
const char space = ' ';
// Instantiate a new state machine in the 'off' state
var onOffSwitch = new StateMachine<string, char>(off);
// Configure state machine with the Configure method, supplying the state to be configured as a parameter
onOffSwitch.Configure(off).Permit(space, on);
onOffSwitch.Configure(on).Permit(space, off);
Console.WriteLine("Press <space> to toggle the switch. Any other key will exit the program.");
while (true)
{
Console.WriteLine("Switch is in state: " + onOffSwitch.State);
var pressed = Console.ReadKey(true).KeyChar;
// Check if user wants to exit
if (pressed != space) break;
// Use the Fire method with the trigger as payload to supply the state machine with an event.
// The state machine will react according to its configuration.
onOffSwitch.Fire(pressed);
}
}
}
}