【说在前面的话】
我们常说状态机是一种思维方式、一种工具,同时它也是一种拥有极高自由度的语言。说到语言,类比我们日常使用的口语,你会发现:有的人表达能力很强——说话条理清晰、逻辑严密、详略得当——能充分表达自己意图的同时还很凝练;相对的,有人颠三倒四、缺乏逻辑性还罗里吧嗦一大堆——在需要认真交换观点(而不是闲聊)的场合,往往沟通双方都很憋屈——大有一副茶壶里煮饺子,有货倒不出的感觉。其实,作为一种翻译思维的语言工具,不同人在使用状态机时也有类似的表达能力的问题。
回顾下之前介绍的内容:
- 《从零开始的状态机漫谈(1)——万物之始的语言》一方面介绍了状态机在计算机科学中的核心地位,另一方面着重介绍了一种嵌入式环境下容易使用的状态机图例;
- 《从零开始的状态机漫谈(2)—— switch:你的状态机初恋》介绍了一种以switch为核心的状态图翻译方式;
本文介绍的设计原则对状态机来说虽然是具有通用意义的,但所使用的图例以及对应的代码翻译规则却是建立在前两篇文章的基础上的,因此还没有阅读过以上内容的小伙建议首先通过上述链接阅读下之前的内容。
【功能单一原则】
人类是视觉主导的“动物”,具体表现为:对于同样的信息,一张优秀的图片往往能让人秒懂,而对应的优秀文字描述哪怕写的简单易懂,人们通常也需要花费数倍的时间来阅读。这里的原因其实很简单——对于图片,人类是并行处理的;而对于建立在阅读之上才能理解的文字,人类采用的是一种“连蹦带跳”的顺序处理方式。并行和顺序处理的在时间效率上的差异,可见一斑。
在普通的应用逻辑中,使用状态图描述逻辑也具有这种“让人一目了然”的潜力;理论上,通过读图理解设计者意图的速度应该远高于直接阅读翻译后代码的速度——遗憾的是,实践中由于缺乏正确的设计原则指导,很多人绘制的状态图恐怕还不如代码看起来好懂。空口白牙,抽象的很,我们不妨举个例子:
一般来说,在全状态机开发下,永远都应该“先画图”,觉得逻辑没有问题的情况下,再“根据状态图来无脑的翻译代码”——这对一张白纸的初学者来说往往很容易做到;遗憾的是,对大部分已经有几年工作经验,习惯了线性逻辑开发的人来说就有点困难了。比如,当我们说要设计一个输出字符串的状态机,对很多人来说,首先出现在大脑中的不是一张状态图,而是类似如下函数的一个参考代码:
代码语言:javascript复制//! brief 通过外设非阻塞的输出一个字节extern bool serial_out(uint8_t cbByte);
void print_str(const char *pchStr){ if (NULL == pchStr) { return ; } //! C语言中,字符串一般以 '