2010-02-02 149 views
8

有限状态机在OOP中通常被认为是糟糕的设计吗?有限状态机:糟糕的设计?

我听到很多。而且,在我必须研究一个非常古老的,无证件的C++使用它之后,我倾向于同意。调试很痛苦。

关于可读性/可维护性的问题呢?

+0

相关:http://stackoverflow.com/questions/1647631/c-state-machine-design – jldupont 2010-02-02 00:37:30

+7

作为一个虔诚的Pastafarian ,FSM总是很好;) – richo 2010-02-02 00:56:55

+7

从来没有诅咒过整个方法,因为你正在考虑一个糟糕的实现。任何没有记录/难以调试的东西都不好,但是它的实现很糟糕。 – 2010-02-02 01:11:20

回答

16

FSM永远不应该被认为是坏的。他们太有用了,但不习惯他们的人往往会认为他们很累。

有很多方法可以用OOP来实现。有些比其他人丑。你的低级别的人会使用switch语句,跳转表,甚至是“goto”。

如果你正在寻找一个更干净的方法来做到这一点,我建议Boost's State Chart library,它建立只是为了在C++中实现UML状态图。它利用现代模板技术,使事物更具可读性。它也表现得很好。

+4

+1为说明和Boost链接本身包含在第一页由罗伯特C.马丁称为“UML教程:有限状态机”的PDF链接。任何人进入面向对象/状态机的经典之作。 – SyntaxT3rr0r 2010-02-02 01:17:06

+0

“永不”是一个非常极端的观点。国际海事组织在适用的情况下存在一些狭窄的情况。即使那样,我还没有看到一个干净的实现,不需要大量的纪律来正确使用(包括boost状态图)。 – Catskul 2016-12-28 20:49:21

1

我认为如果代码是有据可查的,使用面向对象的方法实现它是没有问题的。大多数C/C++使用switch语句来实现FSM,如果机器很大,有时可能会降低可读性。

最近我需要解析一个正则语言,并使用OOP方法实现FSM,代码的可读性和可维护性都很好。我的意思是,比使用大型开关语句好得多。

提示,在第一时刻,我已经实现了FSM包含状态和包含转换的状态。然而,就我而言,事实证明有一个更好的方法可以让一个班级代表FSM,其中包含一组州和另一个州的过渡。对我来说,克隆机器变得更加容易(这对我来说是必需的),并且具有更小的转换功能。

我希望它有帮助, 卡洛斯。

2

我会说有限状态机比其他解决相同问题的方法(比如匹配常规语言的问题)更容易调试。有关FSM的好处都在名称之内......您可能有一个状态机有15个状态,所以您可以在显示所有转换的纸上绘制图表。您可以使用该图来找出系统的有用属性,例如它接受哪些字符串以及它如何进入错误状态。随着更复杂的系统,图表通常是困难的或不可能的。

即使那些说“gotos是邪恶的”的人认为他们是实现状态机的正确方式。 (当然,有些人认为gotos总是邪恶的......但你不能取悦每个人)。

5

不能告诉你他们说什么。

但OO和FSM sorta攻击不同的问题域。在一个对象正在进行交互的领域 - 这就要求采用面向对象的方法。在世界处于一种或另一种状态的领域 - 这就要求采用FSM设计。

实际上,您可以将这些设计与/以不同的抽象级别混合使用,这会比仅使用一种或另一种抽象更清晰。

6

有限状态机是实现某些目标的工具。作为任何工具,它们也可能被滥用。

他们并不是最亲切的工具,但他们擅长的工作几乎不可能通过其他方式实现(通常任何其他方法都注定要比机器差一千倍)。

该作业在经典等待状态被禁止的条件下运行。

我必须阅读触摸屏。为了阅读这个位置,我必须通过SPI交换大约15个命令。我需要每秒100个读数。我必须在每个命令之后等待大约1微秒,因为在我继续之前,相应的繁忙旗帜会消失。还有一些其他操作必须通过相同的界面来实现,例如设置对比度,更改模式,打开或关闭背光,读取温度。如果我为每次等待执行while(BUSY_BIT);,我会在瞬间消耗所有的CPU。如果我做了sched_yield()usleep(1),我永远不会达到我想要的读数数量。唯一的办法是有限状态机。

但也有办法让有限状态机玩起来也不错。在幕后隐藏机器并为开发人员提供功能。

迄今为止,我的工作经验是由2个基于3个不同有限状态机的系统所支配。

  1. 一个大型的门户网站,在每一步你从数据库中检索一些数据,并在此基础上准备更多的查询。在最后一步中,您使用数据生成HTML。每个任务 - 一个网页模块 - 被实现为一个从引擎继承的PHP类。状态被保存在类变量中。每一步都是一个独立的功能。在一个步骤结束时,优化存储的查询并通过缓存将其发送到引擎,并将答案提供回原始。
  2. 具有许多子系统的嵌入式设备。使用任务泵。每个模块注册一个从主循环中每秒调用多次的处理程序。处理程序可以使用状态来保存静态或类变量中的状态。这种协作式多任务处理允许比在独立线程中运行所有内存占用更少的内存空间,允许通过注册两次任务来手动设置任务优先级,并使线程以高优先级运行,从而掩盖系统其余部分。
  3. 半解释器。那个触摸屏。函数调用及其等待状态已注册,但每个函数只被调用一次,然后从程序队列中删除。解释器被称为taskpump的任务,执行有限数量的函数,直到遇到标记为等待状态的函数(或超出要调用的函数的数量)。然后继续,直到等待状态消失。其他任务将作业排序为(有时很长的)要执行的函数序列,然后等待结果。通过这种方式,我可以将需要创建的状态数量限制在约4个需要结果的位置。如果命令是“发送,不检查结果”,如“设置对比度”,它们根本不需要离散状态。因此,实际状态是“等待事件并注册请求的数据”,“等待测量”和“读取结果并正确分配它们”。

如果在结构上或顺序写入,代码将是简单的两倍,三倍更清晰。除了它不会工作,或者会表现糟糕的表现。

0

状态机可以用来表示任何类的行为。如果传入事件的顺序对Class行为(组合类)无关紧要,则使用状态模型不会带来特殊好处。

但是,如果某个类的行为取决于传入事件的顺序(顺序类),则状态机表示行为分析和实现的最佳选择。

如果您关心可读性/可维护性,请使用图形表示法。属于不同工程领域的类的行为示例以图形和可执行形式在http://www.StateSoft.org - > State Machine Gallery中呈现。

-Janusz

+0

我不认为这是真的,因为类充分使用了图灵语言。 https://upload.wikimedia.org/wikipedia/commons/a/a2/Automata_theory.svg – Catskul 2016-12-28 21:17:50

1

FSM的可以很容易理解和维护代码是否结构化的正确途径。我实现了在现有工作的FSM,这里是一个骨架模板:

FSM