# 状态模式

# 介绍

  • 一个对象有状态变化
  • 每次状态变化都会触发一个逻辑
  • 不能总是用 if...else 来控制

# 示例

  • 交通信号灯不同颜色的变化

# UML 类图

在这里插入图片描述

# 代码

// 状态(红灯、绿灯、黄灯)
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())

# 场景

# 有限状态机

  • 有限个状态、以及在这些状态之间的变化
  • 如交通信号灯
  • 使用开源 lib:JavaScript-state-machine
  • github.com/jakesgordon/javascript-state-machine

首先进行安装javascript-state-machine库:npm install --save-dev javascript-state-machine

import StateMachine from 'javascript-state-machine'
import $ from 'jquery'
// 初始化状态机模型
let fsm = new StateMachine({
  init: '收藏',
  transitions: [
    {
      name: 'doStore',
      from: '收藏',
      to: '取消收藏'
    },
    {
      name: 'deleteStore',
      form: '取消收藏',
      to: '收藏'
    }
  ],
  methods: {
    // 监听执行收藏
    onDoStore: function() {
      console.log('收藏成功')
      updateText()
    },
    // 监听取消收藏
    onDeleteStore: function() {
      console.log('取消收藏')
      updateText()
    }
  }
})
let $btn = $('#btn1')

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

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

// 初始化文案
updateText()

# 写一个简单的 Promise

# Promise 就是有限状态机
  • Promise 三种状态:pending fullfilled rejected
  • pending --> fullfilled 或者 pending --> rejected
  • 不能逆向变化

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) {
      console.log(state, data)
      // state 当前状态机实例,data-fsm.resolve(xxx)传递的参数
      data.successList.forEach(fn => fn())
    },
    // 监听reject
    onReject: function(state, data) {
      // state 当前状态机实例,data-fsm.resolve(xxx)传递的参数
      data.failList.forEach(fn => fn())
    }
  }
})

// 定义 Promise
class MyPromise {
  constructor(fn) {
    const _this = this
    this.successList = []
    this.failList = []
    fn(function() {
      // resolve 函数
      fsm.resolve(_this)
    }, function() {
      // reject 函数
      fsm.reject(this)
    })
  }
  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://img.alicdn.com/tfs/TB1Ly5oS3HqK1RjSZFPXXcwapXa-238-54.png'
let result = loadImg(src)
result.then(function() {
  console.log('ok1')
}, function() {
  console.log('fail1')
})

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

# 设计原则

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

评 论:

更新: 11/21/2020, 7:00:56 PM