JS設(shè)計(jì)模式-狀態(tài)模式

介紹
  • 一個(gè)對象有狀態(tài)變化
  • 每次狀態(tài)變化都會(huì)觸發(fā)一個(gè)邏輯
  • 不能總是使用if...else來控制
    eg: 紅綠燈 收藏/未收藏
    核心: 狀態(tài)和主體分離
UML類圖
uml_狀態(tài)模式類圖.png
代碼演示
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
    }
    setState(state) {
        this.state = state
    }
    getState() {
        return this.state
    }
}

// 測試代碼
let context = new Context()

let greed = new State('greed')
let yellow = new State('yellow')
let red = new State('red')

// 綠燈亮了
greed.handle(context)
console.log(context.getState())
// 黃燈亮了
yellow.handle(context)
console.log(context.getState())
// 紅燈亮了
red.handle(context)
console.log(context.getState())

場景
  • 有限狀態(tài)機(jī)
  • 寫一個(gè)簡單的Promise
有限狀態(tài)機(jī)
  • 有限個(gè)狀態(tài),以及在這些狀態(tài)間的變化
  • 如交通信號(hào)燈
  • 使用開源lib :javascript-state-machine
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <p>有限狀態(tài)機(jī)</p>
    <button id="btn"></button>
    
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script src="./03-javascript-state-machine.js"></script>
    <script>
        // 狀態(tài)機(jī)模型
        var fsm = new StateMachine({
            init: '收藏',  // 初始狀態(tài),待收藏
            transitions: [
                {
                    name: 'doStore', 
                    from: '收藏',
                    to: '取消收藏'
                },
                {
                    name: 'deleteStore',
                    from: '取消收藏',
                    to: '收藏'
                }
            ],
            methods: {
                // 執(zhí)行收藏
                onDoStore: function () {
                    alert('收藏成功')
                    updateText()
                },
                // 取消收藏
                onDeleteStore: function () {
                    alert('已取消收藏')
                    updateText()
                }
            }
        })

        var $btn = $('#btn')

        // 點(diǎn)擊事件
        $btn.click(function () {
            if (fsm.is('收藏')) {
                fsm.doStore(1)
            } else {
                fsm.deleteStore()
            }
        })

        // 更新文案
        function updateText() {
            $btn.text(fsm.state)
        }

        // 初始化文案
        updateText()
    </script>
</body>
</html>
寫一個(gè)Promise

Promise 三個(gè)狀態(tài)

  • pending 準(zhǔn)備
  • fullfilled 成功 (執(zhí)行resolve)
  • rejected 失敗
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
    <script src="./03-javascript-state-machine.js"></script>
    <script>
        // 模型
        var fsm = new StateMachine({
            init: 'pending',
            transitions: [
                {
                    name: 'resolve',
                    from: 'pending',
                    to: 'fullfilled'
                },
                {
                    name: 'reject',
                    from: 'pending',
                    to: 'rejected'
                }
            ],
            methods: {
                // 成功
                onResolve: function (state, data) {
                    // 參數(shù):state - 當(dāng)前狀態(tài)示例; data - fsm.resolve(xxx) 執(zhí)行時(shí)傳遞過來的參數(shù)
                    data.successList.forEach(fn => fn())
                },
                // 失敗
                onReject: function (state, data) {
                    // 參數(shù):state - 當(dāng)前狀態(tài)示例; data - fsm.reject(xxx) 執(zhí)行時(shí)傳遞過來的參數(shù)
                    data.failList.forEach(fn => fn())
                }
            }
        })

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

                fn(() => {
                    // resolve 函數(shù)
                    fsm.resolve(this)
                }, () => {
                    // reject 函數(shù)
                    fsm.reject(this)
                })
            }
            then(successFn, failFn) {
                this.successList.push(successFn)
                this.failList.push(failFn)
            }
        }

        // 測試代碼
        function loadImg(src) {
            const promise = new MyPromise(function (resolve, reject) {
                var img = document.createElement('img')
                img.onload = function () {
                    resolve(img)
                }
                img.onerror = function () {
                    reject()
                }
                img.src = src
            })
            return promise
        }
        var src = 'http://www.imooc.com/static/img/index/logo_new.png'
        var result = loadImg(src)
        console.log(result)

        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')
        })

    </script>
</body>
</html>
設(shè)計(jì)原則驗(yàn)證
  • 將狀態(tài)對象和主題對象分離,狀態(tài)的變化邏輯單獨(dú)處理
  • 符合開放封閉原則

本文資料來自慕課網(wǎng)-雙越老師-Javascript 設(shè)計(jì)模式系統(tǒng)講解與應(yīng)用視頻課程

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 你不知道JS:異步 第三章:Promises 接上篇3-1 錯(cuò)誤處理(Error Handling) 在異步編程中...
    purple_force閱讀 1,488評論 0 2
  • 弄懂js異步 講異步之前,我們必須掌握一個(gè)基礎(chǔ)知識(shí)-event-loop。 我們知道JavaScript的一大特點(diǎn)...
    DCbryant閱讀 2,867評論 0 5
  • Promise 對象 Promise 的含義 Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函...
    neromous閱讀 8,823評論 1 56
  • 參考深入理解 Promise 五部曲 -- 1.異步問題[http://www.ghostchina.com/pr...
    合肥黑閱讀 2,430評論 0 14
  • 摘自:阮一峰 http://es6.ruanyifeng.com/#docs/promise 一、首先,我們要弄明...
    泡杯感冒靈閱讀 850評論 0 4

友情鏈接更多精彩內(nèi)容