状态机思路在程序设计中的应用(转)

  状态机的概念

  状态机是软件编程中的一个重要概念,比这个概念更重要的是对它的灵活应用。在一个思路清晰而且高效的程序中,必然有状态机的身影浮现。

  比如说一个按键命令解析程序,就可以被看做状态机:本来在A状态下,触发一个按键后切换到了B状态,再触发另一个键后切换到C状态,或者返回到A状态。这就是最简单的按键状态机例子。实际的按键解析程序会比这更复杂些,但这不影响我们对状态机的认识。

  进一步看,击键动作本身也可以看做一个状态机。一个细小的击键动作包含了:释放、抖动、闭合、抖动和重新释放等状态。

  同样,一个串行通信的时序(不管它是遵循何种协议,标准串口也好、I2C也好;也不管它是有线的、还是红外的、无线的)也都可以看做由一系列有限的状态构成。

  显示扫描程序也是状态机;通信命令解析程序也是状态机;甚至连继电器的吸合/释放控制、发光管(LED)的亮/灭控制又何尝不是个状态机。

  当我们打开思路,把状态机作为一种思想导入到程序中去时,就会找到解决问题的一条有效的捷径。有时候用状态机的思维去思考程序该干什么,比用控制流程的思维去思考,可能会更有效。这样一来状态机便有了更实际的功用。

  程序其实就是状态机。

  也许你还不理解上面这句话。请想想看,计算机的大厦不就是建立在“0”和“1”两个基本状态的地基之上么?

  状态机的要素

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

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

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

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

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

  如果我们进一步归纳,把“现态”和“次态”统一起来,而把“动作”忽略(降格处理),则只剩下两个最关键的要素,即:状态、迁移条件。

  状态机的表示方法有许多种,我们可以用文字、图形或表格的形式来表示一个状态机。

  纯粹用文字描述是很低效的,所以就不介绍了。接下来先介绍图形的方式。

  状态迁移图(STD)

  状态迁移图(STD),是一种描述系统的状态、以及相互转化关系的图形方式。状态迁移图的画法有许多种,不过一般都大同小异。我们结合一个例子来说明一下它的画法,如图1所示。


图1 状态迁移图

  ①状态框:用方框表示状态,包括所谓的“现态”和“次态”。

  ②条件及迁移箭头:用箭头表示状态迁移的方向,并在该箭头上标注触发条件。

  ③节点圆圈:当多个箭头指向一个状态时,可以用节点符号(小圆圈)连接汇总。

  ④动作框:用椭圆框表示。

  ⑤附加条件判断框:用六角菱形框表示。

  状态迁移图和我们常见的流程图相比有着本质的区别,具体体现为:在流程图中,箭头代表了程序PC指针的跳转;而在状态迁移图中,箭头代表的是状态的改变。

  我们会发现,这种状态迁移图比普通程序流程图更简练、直观、易懂。这正是我们需要达到的目的。  

  状态迁移表

  除了状态迁移图,我们还可以用表格的形式来表示状态之间的关系。这种表一般称为状态迁移表。

  表1就是前面介绍的那张状态迁移图的另一种描述形式。

  表1 状态迁移表

  ①采用表格方式来描述状态机,优点是可容纳更多的文字信息。例如,我们不但可以在状态迁移表中描述状态的迁移关系,还可以把每个状态的特征描述也包含在内。

  ②如果表格内容较多,过于臃肿不利于阅读,我们也可以将状态迁移表进行拆分。经过拆分后的表格根据其具体内容,表格名称也有所变化。

  ③比如,我们可以把状态特征和迁移关系分开列表。被单独拆分出来的描述状态特征的表格,也可以称为“状态真值表”。这其中比较常见的就是把每个状态的显示内容单独列表。这种描述每个状态显示内容的表称之为“显示真值表”。同样,我们把单独表述基于按键的状态迁移表称为“按键功能真值表”。另外,如果每一个状态包含的信息量过多,我们也可以把每个状态单独列表。

  ④由此可见,状态迁移表作为状态迁移图的有益补充,它的表现形式是灵活的。

  ⑤状态迁移表优点是信息涵盖面大,缺点是视觉上不够直观,因此它并不能取代状态迁移图。比较理想的是将图形和表格结合应用。用图形展现宏观,用表格说明细节。二者互为参照,相得益彰。

  用状态机思路实现一个时钟程序

  接下来,我将就状态机的应用,结合流程图、状态迁移图和状态迁移,举一个实际例子。下面这张图是一个时钟程序的状态迁移图,如图2所示。


图2 时钟程序状态迁移图

  把这张图稍做归纳,就可以得到它的另一种表现形式——状态迁移表,如表2所示。

  表2 时钟程序状态迁移表

  状态机应用的注意事项

  基于状态机的程序调度机制,其应用的难点并不在于对状态机概念的理解,而在于对系统工作状态的合理划分。

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

  初学者的另一种比较致命的错误,就是在状态划分时漏掉一些状态,我称之为“漏态”。

  “伪态”和“漏态”这两种错误的存在,将会导致程序结构的涣散。因此要特别小心避免。  

  更复杂的状态机

  前面介绍的是一种简单的状态结构。它只有一级,并且只有一维,如图3所示。


图3  线性状态机结构

  如果有必要,我们可以建立更复杂的状态机模型。

  1. 多级状态结构

  状态机可以是多级的。在分层的多级状态机系统里面,一个“父状态”下可以划分多个“子状态”,这些子状态共同拥有上级父状态的某些共性,同时又各自拥有自己的一些个性。

  在某些状态下,还可以进一步划分子状态。比如,我们可以把前面的时钟例子修改如下:

  把所有和时钟功能有关的状态,合并成1个一级状态。在这个状态下,又可以划分出3个二级子状态,分别为显示时间、设置小时、设置分钟;

  同样,我们也可以把所有和闹钟功能有关的状态,合并成1个一级状态。在这个状态下,再划分出4个二级子状态,分别为显示闹钟、设置“时”、设置“分”、设置鸣叫时间。

  我们需要用另一个状态变量(寄存器)来表示这些子状态。

  子状态下面当然还可以有更低一级的孙状态(子子孙孙无穷尽也),从而将整个状态体系变成了树状多级状态结构,如图4所示。


图4 树状多级状态结构

  2. 多维状态结构

  状态结构也可以是多维的。从不同的角度对系统进行状态的划分,这些状态的某些特性是交叉的。比如,在按照按键和显示划分状态的同时,又按照系统的工作进程做出另一种状态划分。这两种状态划分同时存在,相互交叉,从而构成了二维的状态结构空间。

  举一个这方面的例子,如:空调遥控器,如图5所示。


图5 多维状态机结构

  同样,我们也可以构建三维、四维甚至更多维的状态结构。每一维的状态都需要用一个状态变量(寄存器)来表示。

  无论多级状态结构和多维状态结构看上去多么迷人,匠人的忠告是:我们依然要尽可能地简化状态结构,能用单级、单维的结构,就不要给自己找事,去玩那噩梦般的复杂结构。

  简单的才是最有效的。

  结束语

  对状态机的理解需要一个由浅入深的过程。这个过程应该是与实践应用和具体案例思考相结合的。当一种良好的思路成为设计的习惯,它就能给设计者带来回报。愿这篇手记里介绍的基于状态机的编程思路能给新手们带来一些启迪,帮助大家找到“程序设计”的感觉。

http://kb.cnblogs.com/page/528971/

 

时间: 2024-10-04 00:39:21

状态机思路在程序设计中的应用(转)的相关文章

网络程序设计中的模块化思维

程序|设计|网络 首先,以实际例子说明模块化对于程序编写的重要性.例子就是我们现在采用的动网论坛 1 论坛的配色是一个论坛保持活力的基础,一个好的配色意味着一个论坛成功了一半.但我认为动网论坛的配色是及其浪费资源的,同时后台操作也异常麻烦.首先,它将CSS的各个定义部分存储到数据库,在打开页面时再调用,如--------------------------<%'打开数据库代码省略dim bgcolor1bgcolor1=rs("bgcolor1")rs.closeset rs=n

javascript状态机及在工作流中的应用

状态机 什么叫状态机(Finite State Machine),书面上的解释可以自己借助搜索引擎寻找到.通俗地来讲是一个状态定义.查找.切换和事件派发等一系列的代码的集合.与之对应的设计模式叫状态机模式,常用于游戏编程,而在工作流的应用中也会用到. 在工作流中,我们经常会有一系列的步骤:步骤1.步骤2.步骤3.步骤4.我们首先需要定义出这些步骤,再定义这些步骤切换的条件,在客户端的话,一般是某些条件验证通过,可以是字段,也可以是一些接口,还有就是前一个步骤的完成情况. 工作流 我们要完成一项较

在ASP程序设计中在使用Response对象 2003

response|程序|对象|设计 Response对象在ASP程序设计中的主要功能是从浏览器端到服务器端传送数据到浏览器的客户端,我们知道ASP的脚本是在服务器端执行的,他并没有输出"值"的功能.要想拥有输出"值",就必须依靠Response对象. 在这里我们将关注其最常用的一些功能.也就是在程序设计中经常要用到的一些功能,具体如下: (1).response.write 发送信息到浏览器 (2). response.end 有效地中止代码 (3).respons

浅谈ASP程序设计中数据库文件调用的捷径

程序|设计|数据|数据库 引言 本文针对ASP程序设计中最基础.也是最关键的部分"数据库文件的调用"进行说明,同时谈谈ASP程序设计中数据库文件调用的一些技巧. ASP简介 ASP(Active Server Pages)是微软于1996年推出的Web应用程序开发技术,它是一种脚本语言.ActiveX组件及HTML语言等的综合,微软把它描述为"一个服务器的脚本环境,在这里可以生成和运行动态的.交互的.高性能的Web服务器应用程序".其主要功能是为生成动态的.交互式的

在ASP程序设计中在使用Response对象

   Response对象在ASP程序设计中的主要功能是从浏览器端到服务器端传送数据到浏览器的客户端,我们知道ASP的脚本是在服务器端执行的,他并没有输出"值"的功能.要想拥有输出"值",就必须依靠Response对象. 在这里我们将关注其最常用的一些功能.也就是在程序设计中经常要用到的一些功能,具体如下: (1).response.write 发送信息到浏览器 (2). response.end 有效地中止代码 (3).response.redirect 页面重定

嵌入式实时程序设计中C/C++代码的优化

1 引言 计算机技术和信息技术的高速发展的今天,计算机和计算机技术大量应用在人们的日常生活中,嵌入式计算机也得到了广泛的应用. 嵌入式计算机是指完成一种或多种特定功能的计算机系统,是软硬件的紧密结合体.具有软件代码小.高度自动化.响应速度快等特点. 特别适合于要求实时和多任务的应用体系.嵌入式实时系统是目前蓬勃发展的行业之一. 但是,实时嵌入式系统的特点使得其软件受时间和空间的严格限制,加上运行环境复杂,使得嵌入式系统软件的开发变得异常困难. 为了设计一个满足功能.性能和死线要求的系统,为了开发

在ASP程序设计中使用Response对象

Response对象在ASP程序设计中的主要功能是从浏览器端到服务器端传送数据到浏览器的客户端,我们知道ASP的脚本是在服务器端执行的,他并没有输出"值"的功能.要想拥有输出"值",就必须依靠Response对象. 在这里我们将关注其最常用的一些功能.也就是在程序设计中经常要用到的一些功能,具体如下: (1).response.write 发送信息到浏览器 (2). response.end 有效地中止代码 (3).response.redirect 页面重定向 如

编程-windows程序设计中MM_ANISOTROPIC使用问题

问题描述 windows程序设计中MM_ANISOTROPIC使用问题 SetWindowExtEx, 用于设置逻辑坐标范围. SetViewPortExtEx, 用于设置设备坐标范围. 那么,如果存在以下代码: SetMapMode(hdc,MM_ANISOTROPIC); SetWindowExtEx(hdc,200,200,NULL);//将窗口的逻辑坐标X轴0 到200,Y轴设置为0 到200 //将视口原点设置为客户区的中心点上 SetViewportOrgEx(hdc,rectCli

c++-C++大神求思路对视频中行走的人的步态以及行走速度的测量

问题描述 C++大神求思路对视频中行走的人的步态以及行走速度的测量 我想做一个对视频中行走的人的步态以及行走速度的测量,用opencv可以实现吗?有没有相关程序demo推荐下呀,简单思路也行,求大神指点~~~ 解决方案 http://wenku.baidu.com/link?url=5lSvJ3EWYJE06XIYpeeTZAvvKlponeQWh5XoV5CtE7YoXibH-GRiD-FYi_jipSqDqPjOJhw0fqDAo9IfpiEUyW2-6BFZ6vQfUigxgOucrkO