前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >纯粹炫技

纯粹炫技

作者头像
我不是码神
发布2022-07-28 15:56:35
1810
发布2022-07-28 15:56:35
举报
文章被收录于专栏:流媒体技术

最近在搞原子状态机,后续会发文章介绍。

代码语言:javascript
复制
export const enum FSM_EVENT {
  START = 'start',
  START_SUCCESS = 'startSuccess',
  START_FAILED = 'startFailed',
  STOP = 'stop',
  STOP_SUCCESS = 'stopSuccess',
  STOP_FAILED = 'stopFailed',
};
export const enum FSM_STATE {
  IDLE,
  STARTING,
  RUNNING,
  STOPING,
}
const Transitions = [
  {
    [FSM_EVENT.START]: FSM_STATE.STARTING,
  },
  {
    [FSM_EVENT.START_SUCCESS]: FSM_STATE.RUNNING,
    [FSM_EVENT.START_FAILED]: FSM_STATE.IDLE,
  },
  {
    [FSM_EVENT.STOP]: FSM_STATE.STOPING,
  },
  {
    [FSM_EVENT.STOP_SUCCESS]: FSM_STATE.IDLE,
    [FSM_EVENT.STOP_FAILED]: FSM_STATE.RUNNING
  }
] as const;

这个状态机是写死的四种状态

下面是正常的改变状态的过程

代码语言:javascript
复制
private transition(event: FSM_EVENT, ...args: any[]) {
    const to = Transitions[this.state]?.[event];
    if (typeof to == 'number') {
      this.state = to;
      return true;
    }
    return false;
  }
}

到这里没什么问题,但是我盯着最上面的代码看,总觉得里面有重复的东西需要优化。

开始和结束有相同的状态变化过程,而且看着这张图总有种对称性,似乎我们的代码太过肤浅了,没有那个玄而又玄的味道。

直觉上来说四种状态对应着两个二进制位,00、 01、 10 、11,也可以作为数组的下标,0,1,2,3。

这里面一定可以用数学来计算。

现在有六种事件,但是抽出重复的单词,实际上还是四个单词的组合:start、stop、Success、Failed,所以这四个单词也可以用00、01、10、11表示。

代码语言:javascript
复制
export enum FSM_EVENT {
  start,
  stop,
  Success,
  Failed
}
export enum FSM_STATE {
  IDLE = 0b11,
  STARTING = 0b00,
  RUNNING = 0b10,
  STOPPING = 0b01
}

整理一下状态机:得到下面

代码语言:javascript
复制
const Transitions = [];
Transitions[0b00] = {
  [FSMEvent[0b00] + FSMEvent[0b10]]: 0b10,
  [FSMEvent[0b00] + FSMEvent[0b11]]: 0b11,
};
Transitions[0b01] = {
  [FSMEvent[0b01] + FSMEvent[0b10]]: 0b11,
  [FSMEvent[0b01] + FSMEvent[0b11]]: 0b10,
};
Transitions[0b10] = {
  [FSMEvent[0b01]]: 0b01
};
Transitions[0b11] = {
  [FSMEvent[0b00]]: 0b00
};

现在的问题是,如果通过输入:当前状态和事件,得到输出:下一个状态(或者不变)

我们已经把startSuccess事件拆成了,start+Success了,所以相当于有三个输入量,当前状态、X、Y。

反复观察上面的规律,可以发现 下一个状态值 ,就是 X^Y (异或)。

现在剩下如何判断是否跳转到下一个状态了。

00 状态下只接受 X =00,01状态下只接受X = 01 ,那这个好办就是state ^ X == 00

10 状态下只接受 X = 01 ,11 状态下只接受X = 00 ,这个也好办就是state ^ X == 11

再考虑一下其他情况,Y只能是10 和 11,但是下面两个状态变化中没有Y,所以给Y 为0,这样也能保证下一个状态是X^Y。

最后我们整理到一个判断里面即可:

代码语言:javascript
复制
 private transition(x: FSM_EVENT.start | FSM_EVENT.stop, y: 0 | FSM_EVENT.Success | FSM_EVENT.Failed, ...args: any[]) {
    const from = this.state.value;
    const event = FSM_EVENT[x] + (y ? FSM_EVENT[y] : "")
    if ((from ^ x) == (y ? 0 : 3)) {
      this.state.value = x ^ y;
      return true;
    }
    return false;
  }
}

至此我们消灭了一坨看似无法消灭的代码。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-12-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档