故事起源于最近看一位朋友在实现一个 播放/暂停 按钮时, 一些思路上的碰撞,
于是整理出本文, 讲解一下如何用 有限状态机 使代码更简洁可靠.
我们想实现上面这样的按钮交互, 先看看原版实现:
$('#botton').on('click', function(){
if ( $(this).text() === 'OFF' ){
//把按钮的文案改变一下
$(this).text('ON');
//开始播放
$('#player').start();
} else {
$(this).text('OFF');
$('#player').stop();
}
});
这是一个基本的实现方式, 也是一个最简单的方式.
不过,
按照这个方式来做有几个不太优雅的地方:
- 如果点击按钮之后, 需要做的操作增加, 会让
if / else
里面的代码越来越臃肿. - 如果按钮的变化不止
on/off
两种, 我们可能需要些一堆else if
或者用switch / case
针对以上状况, 我提议试试使用有限状态机来解决问题
先看代码:
var fsm = (function(){
//初始状态
var status = 1;
//状态对应的操作
var mapping = {
'1': {
text:'ON',
action: $('#player').start
},
'-1': {
text:'OFF',
action: $('#player').stop
},
};
return function(btn){
//通过 *-1 实现status从 1/-1 切换
status *= -1;
btn.text( mapping[status].text );
var fn = mapping[status].action;
fn();
}
})();
$('#botton').click(function(){
fsm(this);
});
阅读上面代码能发现, 对botton
的点击事件处理, 只需要调用fsm
函数即可, 内部的变化和操作, 都不需要暴露出来.
fsm
内部, 通过mapping
来定义和限制行为, 唯一能够改变的只有status
,
这样的好处在于, 能够避免在编码过程中人为的错误, 因为事件响应部分只能有限的操作状态机的status
,而不是直接参与botton
的行为与表现.
同时, 功能的扩展, 状态的增减, 都只需要在mapping
里面定义好, 非常利于扩展与维护.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。