开始使用状态机来编写你的代码吧!

阅读 2908
收藏 44
2018-10-17
原文链接:mp.weixin.qq.com

在很早的时候就听说过状态机这个名词,但可惜一直没有深入了解过。在 Android 的源码中提供了 StateMachine 这个类,比如 Android 底层的 WifiService 就是用状态机来管理的。第一次深入了解状态机,是在公司的一次分享之夜上,我的一位好朋友 @nixzhu 分享了他在开发 iOS 应用中是如何通过状态机来编写维护管理自己的代码。在学习之后,我也开始尝试使用状态机来编写代码,在下面的文章中,我会向大家介绍,为什么要使用状态机?使用状态机会带来什么好处?如何自己实现一个简单的状态机?

准确的说,是有限状态机,维基百科是这样定义的:有限个状态以及在这些状态之间的转移和动作等行为的数学模型称为状态机。从定义中我们可以摘取出核心的内容:有限个状态、通过外部操作引起状态的转移、数学模型。前两个很好理解, 那么什么是数学模型呢?数学模型是指:关于部分现实世界和为一种特殊目的而作的一个抽象的、简化的结构。本质是通过多重复杂的场景,抽象出一种共性的模型结构。这样就意味着,在状态机的使用上,与技术语言无关,无论你是写 Android 还是写 iOS 或其他的方向都可以采用采用状态机来管理自己的代码。

为什么要使用状态机? 我们在日常工作开发中,一定遇到过这样的场景:当某一个 button 满足某种状态的时候是可点击状态的,当不满足时是不可点击状态,当用户触发了某个正确的操作,button 从不可点击状态变成了可点击状态,当用户触发了错误的操作,button 从可点击状态变成了错误状态。在我刚工作时,如果写这个逻辑,我会一开始从 button 的点击事件开始入手,然后定义一个变量来控制 button 的状态,根据变量的值来决定 button 点击状态和不可点击状态的 UI 显示,同时还要引入一个额外的判断条件,当用户触发错误的操作的时候,将 button UI 显示为错误状态。嗯,5分钟就可以写完,但当之后又有新的状态引入时,怎么办?只能修改之前的代码,这样的代码毫无设计可言,无数次的修改只会让代码变得越来越乱。

使用状态机有什么好处? 当我们在考虑一个场景的实现的时候,发现如果可以引入状态机来管理,那么采用状态机可以让我们在真正写代码之前,去充分的思考、设计这个场景,尽可能的考虑清楚存在哪些状态、哪些操作会导致状态的转换。同时通过状态机来管理代码,可以让逻辑更加清晰、代码集中、减少耦合度。别人看你的代码的时候,也会很好理解,维护起来也更加轻松。

如何实现一个简单的状态机? 现在你应该对状态机的概念和使用其的目的有了初步的了解了吧?我们再回到最初摘取出的状态机的核心内容:有限个状态、通过外部操作引起状态的转移。我们直接看代码(Kotlin 语法):

stateMap:存储每个状态以及当到达这种状态时执行的方法

transitionMap:key 为当前状态,value 为通过某个操作,转化成的新状态

这两个就对应了我们状态机中的核心内容:有限个状态、通过外部操作引起状态的转移。就这么快一个简单的状态机就完成了。

状态机应用例子:我们现在就来通过这个状态机来设计一个固体、液体、气体转换的场景。在思考设计状态机的时候,我们可以在纸上把现有的状态和状态转化关系画出来,便于我们分析。

固体通过融化变为了液体、液体同时可以通过凝固又变会固体,同时液体还可以通过蒸发变为气体,气体通过浓缩可以变为液体,固体上有一个圆圈,代表初始状态。

因为是有限状态机,所有的目标场景都在我们控制的状态转化关系里面,你可能会说固体也可以直接变成气体啊,是可以,这个就和你考虑的是否完善有关了,所以在写代码之前,一定要尽可能详细的去思考,我们这里就只考虑图中的转化关系,看了这个图之后,是不是逻辑很清晰?我们通过状态机去实现代码,清晰的逻辑一样可以对应到代码中。

在测试代码中,我们定义了 State(固液汽三种状态)、Transition(融化、凝固、蒸发、浓缩四种状态转化触发行为),通过 addTransition()将我们状态转化关系建立起来,听过 initialState()来初始化状态,通过 executeTransition()触发状态转移。这么一看整个逻辑都封装在了我们的状态机里面。

当你遇到一个场景或问题,如果你认为状态机有出场的机会,那么你需要先分析一下这个系统里有哪些需要考虑的状态,以及有哪些可能导致状态转换的操作,然后再用某个数据结构来描述它们。之后是利用外部操作引起状态机的状态转移,然后根据状态机的新状态来引起外部环境的变化。这样,逻辑都被封装在了状态机中。

如果你还有疑问的话可以去看看 @nixzhu 写的这篇文章 【状态机的好处】 https://github.com/nixzhu/dev-blog/blob/master/2015-04-23-state-machine.md

上面用 Kotlin 实现的例子代码在这里: https://github.com/Werb/statemachine

如果你使用 Swift,那这里也有一个不到50行代码的状态机实现: https://github.com/nixzhu/Redstone

好了,现在就开始使用状态机来编写你的代码吧!

探索有趣的新事物 

Android、Kotlin、设计、产品、思考、游戏。

长按关注

如果觉得有意思,那就分享一下啦 

评论