控制结构(3) 状态机(state machine)
// 上一篇:卫语句(guard clause)
// 下一篇:局部化(localization)
基于语言提供的基本控制结构,更好地组织和表达程序,需要良好的控制结构。
前情回顾
上次分析了guard 控制结构,有人说:“可是阅读很多开源代码也是if/else层层嵌套的”。是的,guard控制结构只是一种风格,语言并没有规定你一定要这么写,也没必要。两种风格都能写出逻辑清晰的代码,但是还是有细微差别,嵌套模式下,要写出清晰的代码需要更好的做好函数的分层(见第1节),例如,在分支里只做函数的转发调用,那么,代码也是清晰可读的。
function doSomething(){
if(condition1){
call1();
}else{
if(condition2){
call2();
}else{
call3();
}
}
}
我们来看一个新的结构。
典型代码:
let opening = false;
let opened = false;
let closing = false;
let closed = false;
let step1 = false;
function open(onComplete){
if(closing||closed){
return onComplete(RESULT.CLOSED)
}
if(opening){
return onComplete(RESULT.PENDING);
}
if(opened){
return onComplete(RESULT.SUCCESS);
}
opening = true;
doOpen(function(err){
onComplete(err);
opening = false;
opened = true;
});
}
function close(onComplete){
if(!opened){
return onComplete(RESULT.INVALID_OP);
}
if(closing||closed){
return onComplete(RESULT.PENDING);
}
closing = true;
doClose(function(err){
onComplete(err);
closing = false;
closed = true;
})
}
function start(onComplete){
open((err)=>{
if(err){
return onComplete(err);
}
step1((err)=>{
if(err){
return onComplete(err);
}
step2((err)=>{
onComplete(err);
close((err)=>{
log(`close, ret:${err}`);
})
})
})
})
}
function step1(onComplete){
if(!opened){
return onComplete(RESULT.NOT_OPEN);
}
doStep1(function(err){
step1 = true;
onComplete(err);
});
}
function step2(onComplete){
if(!opened){
return onComplete(RESULT.NOT_OPEN);
}
if(!step1){
return onComplete(RESULT.INVALID_STEP);
}
doStep2(function(err){
onComplete(err);
});
}
结构分析
这段代码使用了多个bool变量来做状态标记,为了安全有序的做好每个异步动作,需要在适当的地方对每个bool标志变量做判断。如果这个流程继续复杂起来,bool变量之间的状态组合会变的更加繁杂,也很容易一不小心就漏掉状态的组合判断,导致难以定位的BUG。此时,我们可以采用一种重要的控制结构。
...
是的,状态机(state machine)结构。我们先来看看使用状态机控制结构改写后的代码:
/**所有的状态*/
const STATE = {
INIT: 0,
OPENING: 1,
OPENED: 2,
STEP1: 3,
STEP2: 4,
CLOSING: 5,
CLOSED: 6,
ERROR: 7
}
/**每个状态都只允许从指定状态转移过来*/
const stateTransfer = {
STATE.INIT: [],
STATE.OPENING: [STATE.INIT],
STATE.OPENED: [STATE.OPENING],
STATE.STEP1: [STATE.OPENED],
STATE.STEP2: [STATE.STEP1],
STATE.CLOSING: [STATE.INIT, STATE.OPENING, STATE.OPENED, STATE.STEP1, STATE.STEP2],
STATE.CLOSED: [STATE.CLOSING],
STATE.ERROR: [STATE.INIT, STATE.OPENING, STATE.OPENED, STATE.STEP1, STATE.STEP2],
}
let state = STATE.INIT;
let stateChangeEvent = null;
function moveTo(err, newState){
let nextState = err ? STATE.ERROR : newState;
if(stateTransfer[nextState].indexOf(state)===-1){
return RESULT.INVALID_STATE_TRANSFER;
}
let oldState = state;
state = nextState;
stateChangeEvent(oldState, state, err);
do();
return RESULT.SUCCESS;
}
function do(){
switch(state){
case STATE.INIT:
moveTo(0, STATE.OPENING);
break;
case STATE.OPENING:
doOpen((err)=>{
moveTo(err, STATE.OPENED);
});
break;
case STATE.OPENED:
doStep1((err)=>{
moveTo(err, STATE.STEP1);
});
break;
case STATE.STEP1:
doStep2((err)=>{
moveTo(err, STATE.STEP2);
});
break;
case STATE.STEP2:
moveTo(0, STATE.CLOSING);
break;
case STATE.CLOSING:
doClose((err)=>{
moveTo(err, STATE.CLOSED);
});
break;
case STATE.CLOSED:
break;
default:
break;
}
}
function start(onStateChange){
stateChangeEvent = onStateChange;
do();
}
语义分析
看上去好像多了很多代码。然而在复杂的异步处理流程中,状态机能清晰地表达逻辑,保证逻辑代码的时序,并在形式推理上发现和消灭漏洞,阅读do里面的逻辑,状态之间的转换直接、明显。编程语言提供了基本的状态标志位:bool变量。这便于让程序员在编程中随意地使用bool变量标记各种状态,但0/1状态标示在稍微复杂一点的状态变化中,就会显得不好用:
- 出现组合爆炸,你需要对多个bool变量做组合判断,这很容易漏掉某个状态组合。
- 设计上的失误,导致bool标志位之间不是正交的,因而任一时刻,程序的状态不能确保唯一,这会导致程序出现未知的时序问题。
事实上,任何程序在运行中本身就是一个状态机:
- 当前在第i行执行
- 根据条件,进入第j行执行
这里的状态就是:
- pc, 也就是program counter, 程序计数器
- condition,改变pc的条件
如果想更清楚地理解这点,可以观看Lamport制作的视频,要看到第2集:
http://lamport.azurewebsites.net/video/intro.html
控制结构(3) 状态机(state machine)的更多相关文章
- 用状态机STATE MACHINE实现有选择的文件转换
用书上的例子实现在解析HTML文本时,对"<>"中的符号不进行字符转换. import sys import string from optparse import O ...
- 控制结构(3): 状态机(state machine)
// 上一篇:卫语句(guard clause) // 下一篇:局部化(localization) 基于语言提供的基本控制结构,更好地组织和表达程序,需要良好的控制结构. 前情回顾 上次分析了guar ...
- Android4.0中蓝牙适配器state machine(状态机)的分析
今天晓东和大家来一起看一下Android4.0中蓝牙适配器(Bluetooth Adapter)的状态机变化的过程.首先,我们需要了解一下,蓝牙适配器究竟有哪些状态,从代码可以清晰地看到(framew ...
- 【UML】-NO.43.EBook.5.UML.1.003-【UML 大战需求分析】- 状态机图(State Machine Diagram)
1.0.0 Summary Tittle:[UML]-NO.43.EBook.1.UML.1.003-[UML 大战需求分析]- 状态机图(State Machine Diagram) Style:D ...
- 【翻译】What is State Machine Diagram(什么是状态机图)?
[翻译]What is State Machine Diagram(什么是状态机图)? 写在前面 在上一篇学习类图的时候将这个网站上的类图的一篇文章翻译了出来,感觉受益良多,今天来学习UML状态机图, ...
- Java Secret: Using an enum to build a State machine(Java秘术:用枚举构建一个状态机)
近期在读Hadoop#Yarn部分的源代码.读到状态机那一部分的时候,感到enmu的使用方法实在是太灵活了,在给并发编程网翻译一篇文章的时候,正好碰到一篇这种文章.就赶紧翻译下来,涨涨姿势. 原文链接 ...
- Raft算法系列教程2:状态机复制 (State Machine Replication)
分区容错如何保证? 在分布式系统设计中,需要遵循CAP理论,如果我们要让一个服务具有容错能力,那么最常用最直接的办法就是让一个服务的多个副本同时运行在不同的节点上.但是,当一个服务的多个副本都在运行的 ...
- State Machine.(状态机)
What is a State Machine? Any device that changes its state from one to another due to some actions a ...
- Finite State Machine 是什么?
状态机(Finite State Machine):状态机由状态寄存器和组合逻辑电路构成,能够根据控制信号按照预先设定的状态进行状态转移,是协调相关信号动 作.完成特定操作的控制中心. 类 ...
随机推荐
- 如何解压 Mac OS X 下的 PKG 文件(网摘)
如何解压 Mac OS X 下的 PKG 文件 原文出处:[Macplay] 有时候我们可能需要解包 PKG 格式的安装文件包,在 OS X 系统下完成该操作并不需要你额外再安装软件,系统内置的命令就 ...
- C#多线程的用法1-简单示例
写在前面:阅读本系列文章即表示你已经知道什么是线程等理论知识,现在正想了解如何正确的使用线程进行编程工作. /// <summary> /// 单线程工作示例 /// </summa ...
- 在Android中使用枚举注解而不是枚举
Enums often require more than twice as much memory as static constants. You should strictly avoid us ...
- ctrl+c 和 ctrl+z 的区别
ctrl+c 和 ctrl+z 的区别 ctrl+c和ctrl+z都是中断命令,但是他们的作用却不一样. ctrl+c是强制中断程序的执行, 而ctrl+z的是将任务中断,但是此任务并没有结束,他仍然 ...
- [undefined,1] 和 [,1]的区别在哪里--认识js中的稀疏数组
事情是这样的 今天我想写一个能快速生成一个自然数数组的函数,就是[0,1,2,3]这样的,然后我写了下面的代码: new Array(10).map((item, index) => { ret ...
- shell 编程案例整理
一.统计成绩文件 [zheng@localhost ~]$ cat score.txt ngsan lisi 81.5 wangwu zhangsan lisi wangwu zhangsan lis ...
- C语言 进程控制---创建进程fork()函数
#include "sys/types.h" #include "stdio.h" #include "stdlib.h" #include ...
- 博文Contents<451--到999—>
积分=排名>2017-05-15这一天还真是厉害了.让我等了5个月时间... 前言:博客中的随笔文章.并非都是笔者的原创文章.有些是听别人说的.有些是书上摘录的.有些是百度的.有些是别人博客的文 ...
- 利用Xtrabackup在不停机的情况下备用数据库迁移
什么是Xtrabackup?答:Xtrabackup是一个对InnoDB做数据备份的工具,支持在线热备份(备份时不影响数据读写),是商业备份工具InnoDB Hotbackup的一个很好的替代品. 下 ...
- Java初学者必知 关于Java字符串问题
摘自 http://developer.51cto.com/art/201503/469443.htm 下面我为大家总结了10条Java开发者经常会提的关于Java字符串的问题,如果你也是Java初学 ...