本文是一篇学习性的文章,学习利用有限状态机的思想来定义javascript组件的方法,欢迎阅读,后续计划会写几篇专门介绍自己利用有限状态机帮助自己编写组件的博客,证明这种思路对于编程实现的价值,目前正在积极构思中。本文代码下载
1. 有限状态机概述
简单说,有限状态机是一种模型,模型都用来模拟事物,能够被有限状态机这种模型模拟的事物,一般都有以下特点:
1)可以用状态来描述事物,并且任一时刻,事物总是处于一种状态;
2)事物拥有的状态总数是有限的;
3)通过触发事物的某些行为,可以导致事物从一种状态过渡到另一种状态;
4)事物状态变化是有规则的,A状态可以变换到B,B可以变换到C,A却不一定能变换到C;
5)同一种行为,可以将事物从多种状态变成同种状态,但是不能从同种状态变成多种状态。
比如一个模拟复选按钮的开关组件可以用状态机这样描述:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
var Switch = function ($elem) { var log = function (fsm, previousState) { console.log('currentState is : ' + fsm.currentState + ((previousState || '') && (' , and previous state is : ' + previousState))); }; return { currentState: 'off', states: { 'on': { to: 'off', action: 'turnOff' }, 'off': { to: 'on', action: 'turnOn' } }, init: function () { var self = this; $elem.on('click', (function () { var args = arguments; return function () { self.transition(args); } })()); log(this); }, transition: function (e) { var old = this.currentState; this.currentState = this.states[old].to; var action = this.states[old].action; (action in this) && this[action](old); }, turnOn: function (fromState) { $elem.addClass('on'); log(this, fromState); }, turnOff: function (fromState) { $elem.removeClass('on'); log(this, fromState); } } }; |
在这个简单示例中,Switch组件共有2种状态,分别是on和off,它要么处于on状态,要么处于off状态,初始状态为off,它有2例行为:turnOff和turnOn,前者能使组件从on状态变化到off状态,后者能使组件从off状态变为on状态,它的行为绑定到了某个DOM元素的点击事件上,以下是我用这段js(switch.js)结合jquery运行,点击按钮三次之后的结果(对应源码中的switch.html):
可以看到当调用s.init()之后打印的是这个组件的初始状态,当点击一次之后,组件从off状态转换到了on状态,点击第二次之后从on状态转换到了off状态,点击第三次又恢复到了on状态。这个例子虽然是一个极其简单的状态机实现,但还是能够比较恰当地说明状态机的思想以及它的优点(逻辑思维清晰, 表达能力强)。在实际工作中,我们可以借助javascript-state-machine来实现基于状态机的组件,它是有限状态机这种模型的一个js的实现库,利用它可以快速定义一个状态机对象,相比我前面举例写出的那种实现,这个库虽然源码只有200多行,但是功能非常完整,API简单好用,值得学习跟实践。
2. 使用javascript-state-machine库实现状态机
只要引入该库的js之后就能通过该库提供的一个全局对象StateMachine,并使用该对象的create方法,生成有限状态机的实例(引自该库官方文档的交通灯例子):
例1(对应demo1.html):
在这个例子中:initial选项用来表示fsm对象的初始状态,events选项用来描述fsm对象所有状态的变化规则,每一种变化规则对应一种行为(不过有可能多个规则会对应同一个行为,在后面你会看到这样的例子)。create方法为实例的每一种行为都添加了一个方法,调用这个方法就相当于触发对象的某种行为,当对象行为发生时,对象的状态就可以发生变化。如以上例子创建的实例将拥有如下行为方法:
1 2 3 4 |
fsm.warn() - 调用该方法,实例状态将从'green'变为'yellow' fsm.panic() - 调用该方法,实例状态将从'yellow'变为'red' fsm.calm() - 调用该方法,实例状态将从'red'变为'yellow' fsm.clear() - 调用该方法,实例状态将从'yellow'变为'green' |
这些方法是StateMachine根据create时配置的events规则自动创建的,方法名跟events规则里面的name属性对应,events规则里面有几个不重复的name,就会添加几个行为方法。同时为了方便使用,它还添加了如下成员来判断和控制实例的状态和行为:
1 2 3 4 5 |
fsm.current - 返回实例当前的状态 fsm.is(state) - 如果传入的state是实例当前状态就返回true fsm.s="crayon-sy">(state) - 如果传入的state是实例当前状态就返回true fsm.ρ明这种思路对于编程实现的价值,目前正在积极构思中。本文代码下载
1. 有限状态机概述简单说,有限状态机是一种模型,模型都用来模拟事物,能够被有限状态机这种模型模拟的事物,一般都有以下特点: 1)可以用状态来描述事物,并且任一时刻,事物总是处于一种状态; 2)事物拥有的状态总数是有限的; 3)通过触发事物的某些行为,可以导致事物从一种状态过渡到另一种状态; 4)事物状态变化是有规则的,A状态可以变换到B,B可以变换到C,A却不一定能变换到C; 5)同一种行为,可以将事物从多种状态变成同种状态,但是不能从同种状态变成多种状态。 比如一个模拟复选按钮的开关组件可以用状态机这样描述:
在这个简单示例中,Switch组件共有2种状态,分别是on和off,它要么处于on状态,要么处于off状态,初始状态为off,它有2例行为:turnOff和turnOn,前者能使组件从on状态变化到off状态,后者能使组件从off状态变为on状态,它的行为绑定到了某个DOM元素的点击事件上,以下是我用这段js(switch.js)结合jquery运行,点击按钮三次之后的结果(对应源码中的switch.html): 可以看到当调用s.init()之后打印的是这个组件的初始状态,当点击一次之后,组件从off状态转换到了on状态,点击第二次之后从on状态转换到了off状态,点击第三次又恢复到了on状态。这个例子虽然是一个极其简单的状态机实现,但还是能够比较恰当地说明状态机的思想以及它的优点(逻辑思维清晰, 表达能力强)。在实际工作中,我们可以借助javascript-state-machine来实现基于状态机的组件,它是有限状态机这种模型的一个js的实现库,利用它可以快速定义一个状态机对象,相比我前面举例写出的那种实现,这个库虽然源码只有200多行,但是功能非常完整,API简单好用,值得学习跟实践。 2. 使用javascript-state-machine库实现状态机只要引入该库的js之后就能通过该库提供的一个全局对象StateMachine,并使用该对象的create方法,生成有限状态机的实例(引自该库官方文档的交通灯例子): 例1(对应demo1.html): 在这个例子中:initial选项用来表示fsm对象的初始状态,events选项用来描述fsm对象所有状态的变化规则,每一种变化规则对应一种行为(不过有可能多个规则会对应同一个行为,在后面你会看到这样的例子)。create方法为实例的每一种行为都添加了一个方法,调用这个方法就相当于触发对象的某种行为,当对象行为发生时,对象的状态就可以发生变化。如以上例子创建的实例将拥有如下行为方法:
这些方法是StateMachine根据create时配置的events规则自动创建的,方法名跟events规则里面的name属性对应,events规则里面有几个不重复的name,就会添加几个行为方法。同时为了方便使用,它还添加了如下成员来判断和控制实例的状态和行为:
在控制台打印这个对象,就可以看到这个对象的所有成员: 还记得前面列出的可以用有限状态机模型的事物特点吧,接下来就用例1来说明javascript-state-machine创建的对象是如何满足状态机模型的要求的: 1)可以用状态来描述事物,并且任一时刻,事物总是处于一种状态 这个例子中创建的交通灯实例,要么处于yellow状态,要么处于red状态,要么处于green状态,所以它是满足第1点的。 2)事物拥有的状态总数是有限的 这个实例最多只有三个状态。 3)通过触发事物的某些行为,可以导致事物从一种状态过渡到另一种状态 fsm.warn,fsm.panic,fsm.cal,fsm.clear这几个行为方法都能改变实例的状态。 |