写代码的时候我们常常需要编写一些状态机相关的代码,比如对于节点状态、硬盘状态、作业状态进行一些处理。
这类代码的一个难点,是如何从代码里搞清楚一个对象的所有状态迁移条件。尤其是如果一个对象的状态迁移,是分散在大量的业务代码里的时候,是非常难以理清楚的。这种情况,主要的方案是:
- 在状态声明的地方,或者是在对象声明的地方,用注释把状态及状态迁移条件写清楚。
- 把对象的所有状态迁移,都集中到一个固定的地方去处理,比如对象所有的状态迁移,都必须由统一的事件来触发,在固定的线程(协程)里进行转换。这样代码会比较集中,尤其是迁移相关的函数会比较集中。
如果对象的状态转换比较复杂,那么对象状态的改变,最好通过API来完成,而不是由业务直接设置状态。
关于状态的拆分,也有一些技巧。比如两个状态之间的转换,转换函数如果耗时太久,那么可以考虑添加一种中间状态。比如节点有两个状态:健康、已移除。那么从健康到已移除,可能中间的时间会非常长,状态迁移函数可能会阻塞很久。那么这时候我们可能会考虑添加一种中间状态,叫“移除中”。那么在移除中的状态下,我们可以做一些移除相关的工作,等到移除工作做完后,状态从“移除中”迁移到“已移除”。
通常,每种状态会对应一个该状态下的action,action通常可以是一个函数。action不是必须的。
另外每个状态机会对应一些事件,事件发生时,需要把事件通知到状态机,当某些条件满足时,状态机就会进行状态的变化。
写代码的时候,尽量定义清楚所有的state,并且让所有的state都有对应的action,并且尽量让所有的状态变换都在action中完成。对于Event的通知,可以让状态机定义出几个特定的API,比如notifyEvent1、notifyEvent2,Event通常是有限的,所以这类API也是有限的。在notifyEventx里去根据不同的状态做出不同的处理,这样整个代码的可维护性会比较好。
网友评论