介绍
- 一个对象有状态变化
- 每次状态变化都会触发一个逻辑
- 不能总是用
if else
来控制
示例
- 交通信号灯不同颜色的变化
UML类图
-
传统UML类图
-
简化后的UML类图
代码演示
js
// 状态(红灯、绿灯、黄灯)
class State {
constructor(color) {
this.color = color;
}
// 设置状态
handle(context) {
console.log(`turn to ${this.color} light`)
context.setState(this)
}
}
// 主体
class Context {
consructor() {
this.state = null
}
// 获取状态
getState() {
return this.state
}
setState(state) {
this.state = state
}
}
// test
let context = new Context()
let green = new State('green')
let yellow = new State('yellow')
let red = new State('red')
// 绿灯亮了
green.handle(context)
console.log(context.getState())
场景
有限状态机
- 有限个状态、以及在这些状态之间的变化
- 如交通信号灯
- 使用开源lib:javascript-state-machine
- github.com/jakesgordon/javascript-state-machine
有限状态机- "收藏"和"取消"
js
// 状态机模型
var fsm = new StateMachine({
init: '收藏', // 初始状态,待收藏
transitions: [
{
name: 'doStore',
from: '收藏',
to: '取消收藏'
},
{
name: 'deleteStore',
from: '取消收藏',
to: '收藏'
}
],
methods: {
// 执行收藏
onDoStore: function () {
alert('收藏成功')
updateText()
},
// 取消收藏
onDeleteStore: function () {
alert('已取消收藏')
updateText()
}
}
})
var $btn = $('#btn')
// 点击事件
$btn.click(function() {
if (fsm.is('收藏')) {
fsm.doStore()
} else {
fsm.deleteStore()
}
})
// 更新文案
function updateText() {
$btn.text(fsm.state)
}
// 初始化文案
updateText()
写一个简单的Promise
- 回顾Promise的语法
js
function loadImg(src) {
const promise = new Promise(function (resolve, reject) {
var img = document.createElement('img');
img.onload = function() {
resolve(img)
}
img.onerror = function() {
reject()
}
img.src = src
})
return promise
}
var src = '';
var result = loadImg(src)
result.then(function(img){
console.log('success 1')
}, function() {
console.log('failed 1')
})
result.then(function(img) {
console.log('success 2')
}, function() {
console.log('failed 2')
})
-
分析:Promise就是一个有限状态机
- Promise三种状态:pending fullfilled rejected
- pending -> fullfilled或者 pending -> rejected
- 不能逆向变化
-
写代码
js
// 模型
var fsm = new StateMachine({
init: 'pending',
transitions: [
{
name: 'resolve',
from: 'pending',
to: 'fullfilled'
},
{
name: 'reject',
from: 'pending',
to: 'rejected'
}
],
methods: {
// 成功
onResolve: function (state, data) {
// 参数:state - 当前状态实例;data - fsm.resolve(xxx) 执行时传递过来的参数
data.successList.forEach(fn => fn())
},
// 失败
onReject: function (state, data) {
// 参数: state - 当前状态实例;data - fsm.reject(xxx) 执行时传递过来的参数
data.failList.forEach(fn => fn())
}
}
})
// 定义Promise
class MyPromise {
// fn 回调函数
constructor(fn) {
this.successList = []
this.failList = []
// 接收两个函数参数,第一个为resolve回调,第二个为reject回调
fn(() => {
// resolve 函数
fsm.resolve(this) // fsm触发onResolve函数
}, () => {
// reject 函数
fsm.reject(this) // fsm触发onResolve函数
})
}
// then函数,successFn failFn 不会立即执行,放进数组里
then(successFn, failFn) {
this.successList.push(successFn)
this.failList.push(failFn)
}
}
// 测试代码
function loadImg(src) {
const promise = new MyPromise(function (resolve, reject) {
let img = document.createElement('img')
img.onload = function() {
resolve(img)
}
img.onerror = function() {
reject()
}
img.src = src
})
return promise
}
let src = 'https://imgxxx';
let result = loadImg(src)
result.then(function() {
console.log('ok1')
}, function() {
console.log('fail1')
})
result.then(function() {
console.log('ok2')
}, function() {
console.log('fail2')
})
设计原则验证
- 将状态对象和主题对象分离,状态的变化逻辑单独处理
- 符合开放封闭原则