Skip to content

状态模式

0、定义

TIP

1、一个对象有状态变化

2、每次状态变化都会触发一个逻辑

3、不能总用 if...else 来控制

1、设计原则验证

  • 1、将状态对象和主题对象分离,状态的变化逻辑单独处理
  • 2、符合开放封闭原则

2、示例

示例:交通信号灯不同颜色的变化

deign

3、代码

js
// 状态 (红灯、绿灯、黄灯)
class State {
    constructor(color) {
        this.color = color
    }
    handle(context) {
        console.log(`turn to ${this.color} light`)
        // 设置状态
        context.setState(this)
    }
}

// 主体
class Context {
    constructor() {
        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())

// 黄灯亮了
yellow.handle(context)
// 打印状态
console.log(context.getState())

// 红灯亮了
red.handle(context)
// 打印状态
console.log(context.getState())

4、经典场景

4.1、有限状态机

js
npm install --save-dev javascript-state-machine --registry=https://registry.npm.taobao.org

npm i jquery --save --registry=https://registry.npm.taobao.org

<button id="btn1"></button>

import StateMachine from 'javascript-state-machine'
import $ from 'jquery'

// 初始化状态机模型
let fsm = new StateMachine({
    init: '收藏',
    transitions: [
        {
            name: 'doStore',
            from: '收藏',
            to: '取消收藏'
        },
        {
            name: 'deleteStore',
            from: '取消收藏',
            to: '收藏'
        }
    ],
    methods: {
        // 监听执行收藏
        onDoStore: function () {
            alert('收藏成功') // 可以 post 请求
            updateText()
        },
        // 监听取消收藏
        onDeleteStore: function () {
            alert('已经取消收藏') // 可以 post 请求
            updateText()
        }
    }
})

let $btn = $('#btn1')

// 按钮点击事件
$btn.click(function () {
    if (fsm.is('收藏')) {
        fsm.doStore()
    } else {
        fsm.deleteStore()
    }
})

// 更新按钮的文案
function updateText () {
    console.log(fsm.state);
    $btn.text(fsm.state)
}

// 初始化文档
updateText()

4.2、写一个简单的 Promise

js
import StateMachine from 'javascript-state-machine'

// 初始化状态机模型
let fsm = new StateMachine({
    init: 'pending', // 初始化状态
    transitions: [
        {
            name: 'resolve', // 事件名称
            from: 'pending',
            to: 'fullfilled'
        },
        {
            name: 'reject', // 事件名称
            from: 'pending',
            to: 'rejected'
        }
    ],
    methods: {
        // 监听 resolve
        onResolve: function (state, data) {
            // state - 当前状态机实例; data - fsm.resolve(xxx) 传递的参数
            data.successList.forEach(fn => fn())
        },
        // 监听 reject
        onReject: function (state, data) {
            // state - 当前状态机实例; data - fsm.reject(xxx) 传递的参数
            data.failList.forEach(fn => fn())
        }
    }
})

// 定义 Promise
class MyPromise {
    constructor(fn) {
        this.successList = []
        this.failList = []

        let self = this;
        fn (function () {
            // resolve 函数
            fsm.resolve(self)
        }, function () {
            // reject 函数
            fsm.reject(self)
        })
    }
    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://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=296930828,2685283461&fm=173&app=25&f=JPEG?w=218&h=146&s=5ECA722382C74AFA0FB548D70100A0A1'
let result = loadImg(src)

result.then(function () {
    console.log('ok1')
}, function () {
    console.log('fail1')
})

result.then(function () {
    console.log('ok2')
}, function () {
    console.log('fail2')
})

Released under the MIT License.