赞
踩
什么是有限状态机,一个系统可以分为很多个状态,通过一定的条件和规则可以触发状态与状态之间的变化。状态的变化过程会触发一系列行为。这种离散状态的流转机制及运行过程就叫有限状态机
通过快捷键可以触发截图,在快捷键按下之前截图系统处于等待状态,在快捷键按下这个条件发生以后,系统进入截图区域选择状态,当按Esc后,系统又回到了等待状态,当鼠标按下并拖动时,系统处于拖动选区状态,当释放鼠标按键时进入等待确认状态,在此状态下,系统弹出选择菜单,可供你对选中的区域图片进行处理。当点击确认按钮后,系统对处理后的图片进行保存,退出截图,重新回到等待状态。
在整个过程中,状态是有限个,状态的变化需要有一个触发条件。触发前后,根据不同输入操作会产生状态分支。
我开发过一个工具就是按这个状态机模型设计的
有限状态机是一种用来进行对象行为建模的工具,其作用主要是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。在计算机科学中,有限状态机被广泛用于建模应用行为、硬件电路系统设计、软件工程,编译器、网络协议、和计算与语言的研究。比如下图非常有名的TCP协议状态机。
为了简化问题,我们来看一个简单版本的格式文本解析问题
有一串文本,将文本中连续出现的空格变成一个,如果空格出现在字符串中则保持不变
例如 一串文本为
- var i = a+b- c % s;
- var s="Hello mmmmmm...";
压缩之后文本会变成
- var i = a+b- c % s;
- var s="Hello mmmmmm...";
这个出来看似不是很复杂,但现实的情况可能比这个复杂的多
状态图类似于这样:
复杂的状态机可能类似于这种
本文最后介绍状态机模型的一种JS实现框架
源码:
GitHub - jakesgordon/javascript-state-machine: A javascript finite state machine library
该JS框架实现了状态的的构建,状态转移命令,命令执行先后触发事件回调,状态变化前后触发回调,状态跳转,状态历史记录回溯,多实例状态共享数据,多实例状态机,状态机可视化,状态转移输入参数,动态状态,动态创建销毁回调
为什么要做这样一个框架,因为很多复杂系统都涉及状态机,使用框架可以最大程度减少重复代码,减少状态和方法的构造,增加对状态机系统的理解和把握。
下面介绍它简单的使用案例
A library for finite state machines.
A state machine can be constructed using:
- var fsm = new StateMachine({
- init: 'solid',
- transitions: [
- { name: 'melt', from: 'solid', to: 'liquid' },
- { name: 'freeze', from: 'liquid', to: 'solid' },
- { name: 'vaporize', from: 'liquid', to: 'gas' },
- { name: 'condense', from: 'gas', to: 'liquid' }
- ],
- methods: {
- onMelt: function() { console.log('I melted') },
- onFreeze: function() { console.log('I froze') },
- onVaporize: function() { console.log('I vaporized') },
- onCondense: function() { console.log('I condensed') }
- }
- });
which creates an object with a current state property:
fsm.state
methods to transition to a different state:
fsm.melt()
fsm.freeze()
fsm.vaporize()
fsm.condense()
observer methods called automatically during the lifecycle of a transition:
onMelt()
onFreeze()
onVaporize()
onCondense()
along with the following helper methods:
fsm.is(s)
- return true if state s
is the current statefsm.can(t)
- return true if transition t
can occur from the current statefsm.cannot(t)
- return true if transition t
cannot occur from the current statefsm.transitions()
- return list of transitions that are allowed from the current statefsm.allTransitions()
- return list of all possible transitionsfsm.allStates()
- return list of all possible statesA state machine consists of a set of States
A state machine changes state by using Transition
A state machine can perform actions during a transition by observing LifeCycle Even
A state machine can also have arbitrary Data and Methods.
Multiple instances of a state machine can be created using a State Machine Factory.
比如官方的物态变化为例子
- var fsm = new StateMachine({
- init: 'solid',
- transitions: [
- { name: 'melt', from: 'solid', to: 'liquid' },
- { name: 'freeze', from: 'liquid', to: 'solid' },
- { name: 'vaporize', from: 'liquid', to: 'gas' },
- { name: 'condense', from: 'gas', to: 'liquid' },
- { name: 'goto', from: '*', to: ()=>['liquid', 'solid','gas'][Math.floor(Math.random()*3)] },
- ],
- methods: {
- onMelt: function() { console.log('I melted') },
- onFreeze: function() { console.log('I froze') },
- onVaporize: function() { console.log('I vaporized') },
- onCondense: function() { console.log('I condensed') }
- }
- });
在状态机构造函数中增加了一个Goto状态,当触发Goto指令时,随机跳转到任何一个状态(跟薛定谔的猫很相似,和上帝之手一样,黑线代表坍缩到真实物理世界能被人理解的转移过程,红线代表随机游走的宇宙本质)
{ name: 'goto', from: '*', to: s=>['liquid', 'solid','gas'][Math.floor(Math.random()*3)] }
状态转移图如下
其中每个椭圆代表状态机的状态,椭圆之间的连线代表那些状态可以相互转移,以及转移的方法,goto是一种特殊的转移指令,当goto指令运行后,会触发转移状态指令运行,
加入,当前状态是gas,通过goto指令操作随机跳转到liquid状态,此时,除了触发转移变化事件,还会触发onCondese事件。
修改前生命周期事件执行的先后顺序为
onBeforeTransition - fired before any transition
onBefore<TRANSITION> - fired before a specific TRANSITION
onLeaveState - fired when leaving any state
onLeave<STATE> - fired when leaving a specific STATE
onTransition - fired during any transition
onEnterState - fired when entering any state
onEnter<STATE> - fired when entering a specific STATE
on<STATE> - convenience shorthand for onEnter<STATE>
onAfterTransition - fired after any transition
onAfter<TRANSITION> - fired after a specific TRANSITION
on<TRANSITION> - convenience shorthand for onAfter<TRANSITION>
修改后,比原来多监测了3种事件:
onBeforeTransition - fired before any transition
onBeforeGoto - fired before Goto
onBefore<Transition>-触发与Goto前后状态相同的Before转移方法
onLeaveState -在Goto转移指令之前的任何状态变化后执行
onLeave<STATE> - 在Goto转移指令之前的指定状态变化后执行
onTransition - 任何转移指令触发时执行
onEnterState - 转移至任何状态后执行
onEnter<STATE>/on<STATE> - 转移至指定状态后执行
onAfterTransition - 任何转移指令触发后执行
onAfterGoto/onGoto - fired after Goto
onAfter<Transition>/on<Transition>-触发与Goto前后状态相同的After转移方法
修改之前的源码
修改后
系统同时监听额外三种事件
调用代码
- //状态机工厂
- StateMachine.factory(Analyse, {
- init: "init",
- transitions: [{
- name: "create val",
- from: "init",
- to: "word"
- },{
- name: "create assign",
- from: "word",
- to: "assign"
- }
- ,{
- name: "create value",
- from: "init",
- to: "number"
- }, {
- name: 'goto',
- from: '*',
- to: function() {
- var keystate = this.NextKey();
-
- this.Codesplit.push(keystate);
- return keystate.key;
- },
- dot: {
- label: "ss"
- }
- }],
- data: {
- Codesplit: []
- },
- methods: {
- onAfterInit:function(){
- //解析对象初始化
- this.AnalyseDom=new Squence();
- this.DomPoint=this.AnalyseDom;
- },
- onCreateVal: function() {
- if(this.DomPoint instanceof Squence){
- var keyvalue = this.Codesplit.pop();
- var val;
- if(this.DomPoint.VarSpace.Exist(keyvalue.value)){
- val=this.DomPoint.VarSpace.Find(keyvalue.value);
- }else{
- val = new Val(keyvalue.value);
- this.DomPoint.VarSpace.Add(val);
- };
- this.DomPoint.appendChild(val);
- this.DomPoint = val;
- }
- },
-
- onCreateAssign: function() {
- if(this.DomPoint instanceof Val){
- var keyvalue = this.Codesplit.pop();
- var assign = new Assign(this.DomPoint);
- this.DomPoint.parent.replaceLastChild(assign);
- this.DomPoint = assign;
- }else if(this.DomPoint instanceof Value){
- throw "无法对常量进行赋值";
- }else if(this.DomPoint instanceof Method){
- throw "无法对方法进行赋值";
- }
- },
-
- onCreateValue( ){
- if(1==1){
-
- }
- },
- onAssign(){
- if(1==1){
-
- }
- },
- onBeforeTransition: function(lifecycle, arg1, arg2) {
- console.log(lifecycle.transition);
- // 'step'
- console.log(lifecycle.from);
- // 'A'
- console.log(lifecycle.to);
- lifecycle.dot = 'sssss';
- }
-
- },
- plugins: [new StateMachineHistory()// <-- plugin enabled here
- ]
-
- });
-
- var FSM = new Analyse();
修改之后的代码具有很大的优势,比如不需要将所有的状态分支转换逻辑写在同一个方法内,系统根据状态变化,动态的调用已声明的响应回调方法,无需人工判断。
以上部分图片来源于网络,如有侵权,请联系删除。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。