Day08 - 实作一个状态机 - 1

根据需求画出状态图後
https://ithelp.ithome.com.tw/upload/images/20210921/20130721Kh6DzCoDyK.png

  1. 他们都有一个初始状态
  2. 整个实体、物件或是对象,都有一系列不同的状态们
  3. 还有一系列不同的事件,可能会导致状态转移
  4. 还有一张纪录着什麽事件配什麽状态会发生转移的地图、对应表
  5. 有限数量的结束状态( 0 - n 个 )

接着我们便来思考如何实作,
(1). 有初始状态:所以我们需要有个变数( state )来储存状态,而且这个状态的初始值就是初始状态
(2). 一系列的状态们:状态改变时,也应该被储存起来( state )
(3). 事件、转移:当某个状态 + 某个事件会导致状态的转移,nextState = transition(previusState, event),所以要实作一个 function transition,这个 function 里应该会有个 mapping ,记录着什麽状态 + 什麽事件可以转移状态。

(1). 初始状态存入一个变数

const initialState = "站姿、静止"

(3). 事件、转移,实作一个 function transition

关於这个 transition ,首先会想到 input 进去,为了辨识什麽 state, event 来决定要回传什麽,执行辨识的底层实作一定会经历许多逻辑判断,才会回传对应的结果给我们。假设状态会有许多个,如果不想大量使用 if/else ,此时我们想到可以使用 switch/case

const initialState = "站姿、静止"
// 3 实作 transition
function transition (state) {
  switch(state){
    case "站姿、静止": // 3.1 - 过滤状态
      // 3.2 - 回传经过转移後的状态 (回传 nextState )
      return "站姿、移动"
    case "站姿、移动":
      return "站姿、静止"
    case "跳跃中":
      return "站姿、移动"
    case "俯卧、静止":
    case "俯卧、移动":

    default:
      throw "The state is not existed, machine broken"
  }
}

上面的实作中,我们已经能在第一个 switch case 辨识 state ,那促使 state 转移的是什麽呢? 是事件 event,而 transition 则是根据对应的 state 及对应的 event 发生时,改变 state,所以我们接着需要在 state 底下来辨识 event ,才能达到我们说的 某个状态 + 某个事件会导致状态的转移,nextState = transition(previusState, event)

function transition (state,event) {
  switch(state){
    case "站姿、静止": 
      switch(event){
        case "跳跃":
           // 3.2 - 回传经过转移後的状态 (回传 nextState )
           return  "跳跃中"
        case "开始移动":
           return  "站姿、移动"
        case "卧倒":
           return  "俯卧、静止"
        default:
           // 如果 "站姿、静止" 状态,遇到 "跳跃","开始移动","卧倒" 以外的事件
           // 不转移状态
           return state
      }
    case "站姿、移动":
      switch(event){
        case "停止移动":
           return  "站姿、静止"
        default:
           // 如果 "站姿、移动" 状态,遇到 "停止移动" 以外的事件
           // 不转移状态
           return state
      }
    case "跳跃中":
      switch(event){
        case "降落":
           return  "站姿、静止"
        default:
           // 如果 "跳跃中" 状态,遇到 "降落" 以外的事件
           // 不转移状态
           return state
      }
    case "俯卧,静止": // 应该是 "俯卧、静止" 没用常数保护的话,打错就出现 bug 了
      switch(event){
        case "起身":
           return  "站姿、静止"
        case "开始移动":
           return  "俯卧、移动"
        default:
           // 如果 "俯卧、静止" 状态,遇到 "起身", "开始移动" 以外的事件
           // 不转移状态
           return state
      }
    case "俯卧、移动":
      switch(event){
        case "停止移动":
           return  "俯卧、静止"
        default:
           // 如果 "俯卧、移动" 状态,遇到 "停止移动” 以外的事件
           // 不转移状态
           return state
      }
    default:
      throw "The state is not existed, machine broken"
  }
}

(2). 一系列的状态们:状态改变时,也应该被储存起来( state )


const initialState = "站姿、静止"

function transition (state,event) {
  // ...
}

const nextState = transition(initialState,"")  // "站姿、静止"
const nextState2 = transition(initialState,"开始移动")  // "站姿、移动"
const nextState3 = transition(nextState2,"停止移动")  // "站姿、静止"
const nextState4 = transition(nextState3,"卧倒")  // "卧倒、静止"

如此我们便可以根据对应的 state 及 event 来决定要不要进行 transition 了,也算是初步完成我们的 state machine 了。我们来回顾一下现在还缺什麽

  1. State Machine 不完备,没有一个变数能帮我记忆当下的状态是什麽,我在使用 transition 时还要另外用一堆变数来储存 state ,感觉不好维护、也不好维持程序码的连贯性
  2. 当 state 跟 event 都是直接使用字串,很容易打错、出现 bug ,所以想要用常数保护起来
  3. 用双层 switch case 好像比较不好读,感觉也不太好重复使用

明天让我们根据以上不足之处,继续完备一个 State Machine

参考文献


<<:  【Day 08】欢迎来到实力至上主义的 Shellcode (下) - Windows x86 Shellcode

>>:  Day 22:「您好,欢迎登入 Vuta 奇幻世界」- 事件处理

Day 17 | FPS灭火AR游戏开发 Part2 - 火焰粒子系统制作

目录 火焰制作 上一篇实作了简易的粒子系统(水柱),那今天就要实作稍微复杂多层次的粒子系统,那就开...

数位AI化

人的科技文明发展始终来自於人性 在疫情後的时代,所有的一切都将发生改变,这已经是一个不能逆转的趋势了...

[DAY-21] 获得工作机会 谈条件 做出决定

我爱我的工作! 我爱我的工作! 我爱我的工作! 修完 虫虫 直接开夜车 来胡言乱语 不为过吧 !!...

[Q&A] 06 风险评监报告生出来前的修修改改

资讯安全管理制度运行过程中,会对即有的企业或机构文化带来一定的冲击。 顾问有教过、学员有学过都是真的...

谈谈TDD

Google i/o 2017 提到了Android TDD 的参考(https://develop...