探索FSM (有限状态机)应用

这篇具有很好参考价值的文章主要介绍了探索FSM (有限状态机)应用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。。

本文作者:木杪

有限状态机(FSM) 是计算机科学中的一种数学模型,可用于表示和控制系统的行为。它由一组状态以及定义在这些状态上的转换函数组成。FSM 被广泛用于计算机程序中的状态机制。

有限状态机(FSM)应用场景

  • 在各种自动化系统的应用: 例如交通信号灯、地铁站的旋转闸门、银行自动取款机等。通过对状态和转换函数的定义,可以实现对系统行为的精确控制。

    交通信号灯状态流转图

    探索FSM (有限状态机)应用

    地铁站的旋转闸门状态流转图

    探索FSM (有限状态机)应用

    银行自动取款机状态流转图

    探索FSM (有限状态机)应用

  • 在编程领域的应用: 例如在编写编译器和解释器时,可以使用有限状态机(FSM) 来处理词法分析。例如:JSON.Parse

  • 在Notion中应用: 可以使用 有限状态机(FSM) 的相关概念来构建各种工作流程,例如状态转换图、状态转换表等。

  • 在web中应用: 我们熟悉的 Promise 也是一个状态机,具有三个状态:pending、resolved。rejected。

    Promise状态流转图

    探索FSM (有限状态机)应用

    登录功能流转图

    探索FSM (有限状态机)应用

类似这样的状态机的例子数不胜数,甚至于,人也是一种极其复杂的状态机,给定一种刺激或多种刺激组合,也会触发人从某种状态过渡到另一种状态。只不过复杂程度极高,以至于现代科学完全无法解密这种状态机。

有限状态机(FSM)实现原理

具体来说,FSM由以下几部分组成:

  • 初始状态:系统的初始状态。
  • 状态集合:表示系统可能处于的各种状态。
  • 转移函数:定义系统在不同状态之间的转移条件和结果。
  • 终止状态:系统在某个状态下可以停止计算。

有限状态机(FSM) 的实现基于状态转移图状态转移图 是一个有向图,它表示有限状态机(FSM) 中状态之间的转移关系。在状态转移图中,每个状态表示系统的某种状态,每个转移表示系统从一个状态转移到另一个状态的条件和结果。

实现简易的有限状态机(FSM)

实现步骤

  • 当状态机开始执行时,它会自动进入初始化状态(initial state)。
  • 每个状态都可以定义,在进入(onEnter)或退出(onExit)该状态时发生的行为事件(actions),通常这些行为事件会携带副作用(side effect)。
  • 每个状态都可以定义触发转换(transition)的事件。
  • 转换定义了在退出一个状态并进入另一个状态时,状态机该如何处理这种事件。
  • 在状态转换发生时,可以定义可以触发的行为事件,从而一般用来表达其副作用。

状态转移图

探索FSM (有限状态机)应用

function createMachine(stateMachineDefinition) {
  const machine = {
    value: stateMachineDefinition.initialState,
    performTransition(currentState, event) {
      const currentStateDefinition = stateMachineDefinition[currentState];
      const destinationTransition = currentStateDefinition.transitions[event];
      if (!destinationTransition) {
        return;
      }
      const destinationState = destinationTransition.target;
      const destinationStateDefinition =
        stateMachineDefinition[destinationState];

      destinationTransition.action();
      currentStateDefinition.actions.onExit();
      destinationStateDefinition.actions.onEnter();

      machine.value = destinationState;

      return machine.value;
    },
  };
  return machine;
}

const machine = createMachine({
  initialState: "off",
  off: {
    actions: {
      onEnter() {
        console.log("off: onEnter");
      },
      onExit() {
        console.log("off: onExit");
      },
    },
    transitions: {
      switch: {
        target: "on",
        action() {
          console.log('transition action for "switch" in "off" state');
        },
      },
    },
  },
  on: {
    actions: {
      onEnter() {
        console.log("on: onEnter");
      },
      onExit() {
        console.log("on: onExit");
      },
    },
    transitions: {
      switch: {
        target: "off",
        action() {
          console.log('transition action for "switch" in "on" state');
        },
      },
    },
  },
});

let state = machine.value;
console.log(`current state: ${state}`);
state = machine.performTransition(state, "switch");
console.log(`current state: ${state}`);
state = machine.performTransition(state, "switch");
console.log(`current state: ${state}`);

有限状态机(FSM)的 应用实现

在状态比较多的情况下,把状态、事件及 transitions 集中到一个状态机中,进行统一管理。这样不需要写太多的 if-else,或者 case 判断,如果增加状态和事件,也便于代码的维护和扩展。

文本解析器

实现思路

  • 确定状态和输入
    在编写 FSM 之前,我们需要确定我们的状态和输入。在这个例子中,我们将定义三个状态:起始状态、数字状态和字符串状态。我们还将定义四个输入:数字、字母、引号和空格。
  • 定义状态机类
    现在,我们可以编写代码来实现我们的 FSM 。我们需要定义一个状态机类,它将接受输入,并根据转移规则转换状态。该类应该包含以下属性:
    • currentState:当前状态。
    • states:状态列表。
    • transitions:转移列表。
      它还应该包含以下方法:
    • transition:该方法接受一个输入参数 input,根据当前状态以及输入参数,执行相应的状态转换。
  • 定义转移规则
    我们还需要定义状态之间的转移规则。为此,我们将使用转移列表,其中包含状态之间的映射和输入。转移规则应该考虑当前状态和输入,并根据它们确定下一个状态。如果当前状态和输入没有匹配的转移规则,则应该抛出一个异常。
  • 解析文本
    现在,我们可以使用状态机解析文本。我们需要将文本拆分为单词,并将每个单词作为输入提供给状态机。在处理完所有输入后,我们可以通过调用 getInputType 方法来获取解析的令牌。

示例代码

const STATES = {
  START: "start",
  NUMBER: "number",
  STRING: "string",
};

const INPUTS = {
  NUMBER: "number",
  LETTER: "letter",
  SPACE: "space",
  QUOTE: "quote",
};

const TRANSITIONS = [
  {
    currentState: STATES.START,
    input: INPUTS.NUMBER,
    nextState: STATES.NUMBER,
  },
  {
    currentState: STATES.START,
    input: INPUTS.LETTER,
    nextState: STATES.STRING,
  },
  { currentState: STATES.START, input: INPUTS.SPACE, nextState: STATES.START },
  { currentState: STATES.START, input: INPUTS.QUOTE, nextState: STATES.STRING },
  {
    currentState: STATES.NUMBER,
    input: INPUTS.NUMBER,
    nextState: STATES.NUMBER,
  },
  { currentState: STATES.NUMBER, input: INPUTS.SPACE, nextState: STATES.START },
  {
    currentState: STATES.STRING,
    input: INPUTS.LETTER,
    nextState: STATES.STRING,
  },
  { currentState: STATES.STRING, input: INPUTS.SPACE, nextState: STATES.START },
  { currentState: STATES.STRING, input: INPUTS.QUOTE, nextState: STATES.START },
];

class TextParse {
  constructor() {
    this.currentState = STATES.START;
    this.buffer = "";
    this.type;
  }

  performTransition(input) {
    const transition = TRANSITIONS.find(
      (t) => t.currentState === this.currentState && t.input === input.type
    );
    if (!transition)
      throw new Error(
        `Invalid input "${input.value}" for state "${this.currentState}"`
      );

    this.currentState = transition.nextState;

    if (this.currentState === STATES.START) {
      const token = this.buffer;
      const type = this.type;
      this.buffer = "";
      this.type = "";
      return {
        type,
        value: token,
      };
    } else {
      this.buffer += input.value;
      this.type = input.type;
    }
  }
}

function textParse(input) {
  const textParse = new TextParse();
  const tokens = [];

  for (let i = 0; i < input.length; i++) {
    const char = input[i];

    try {
      const token = textParse.performTransition({
        type: getInputType(char),
        value: char,
      });

      if (token) {
        tokens.push(token);
      }
    } catch (e) {
      console.error(e.message);
      return null;
    }
  }

    const lastToken = textParse.performTransition({ type: INPUTS.SPACE });

  if (lastToken) {
    tokens.push(lastToken);
  }

  return tokens;
}

function getInputType(char) {
  if (/[0-9]/.test(char)) {
    return INPUTS.NUMBER;
  } else if (/[a-zA-Z]/.test(char)) {
    return INPUTS.LETTER;
  } else if (/[\s\n\t\r]/.test(char)) {
    return INPUTS.SPACE;
  } else if (char === '"') {
    return INPUTS.QUOTE;
  } else {
    throw new Error(`Unknown input type for "${char}"`);
  }
}

// Example usage:
console.log(textParse('123 abc "def ghi" 456')); 
// [
//   { type: 'number', value: '123' },
//   { type: 'letter', value: 'abc' },
//   { type: 'letter', value: '"def' },
//   { type: 'letter', value: 'ghi' },
//   { type: '', value: '' },
//   { type: 'number', value: '456' }
// ]

示例代码

web 应用

使用 有限状态机(FSM) 结合 React 构建 web 应用,不局限于身份认证,登录,步骤表单,有蛮多 web 应用在
有限状态机(FSM)的实践 ,下面主要描述 从有限状态机(FSM)在服务端拉取数据的状态转移上的应用

  • 状态转移图
    探索FSM (有限状态机)应用

  • 状态集(States), 转换规则(Transitions)

const states = {
  INITIAL: "idle",
  LOADING: "loading",
  SUCCESS: "success",
  FAILURE: "failure",
};
const transitions = {
  [states.INITIAL]: {
    fetch: () => /* Returns states.LOADING */,
  },

  [states.LOADING]: {},

  [states.SUCCESS]: {
    reload: () => /* Returns states.LOADING */,
    clear: () => /* Returns states.INITIAL */,
  },

  [states.FAILURE]: {
    retry: () => /* Returns states.LOADING */,
    clear: () => /* Returns states.INITIAL */,
  },
}

示例代码

总结

结合前端应用的探索体现的不多,可以再作为第二篇内容去探讨,有兴趣的同学可以尝试一下 有限状态机(FSM) 在 web 上的应用探索,以及 Xstate库(FSM封装的功能性库) 的应用,以及跟 状态管理库 差异化的知识。在这里提醒一点,状态管理库 (Redux)Xstate 并不是互斥的,Xstate 关注的是如何设计状态,状态管理库关注的是如何管理状态。事实上,状态机几乎可以与任何无主见的状态管理工具一起使用。我鼓励您探索各种方法,以确定最适合您、您的团队和您的应用程序的方法。文章来源地址https://www.toymoban.com/news/detail-419499.html

参考资料

  • https://statecharts.dev/what-is-a-state-machine.html
  • https://bespoyasov.me/blog/fsm-to-the-rescue/
  • https://xstate.js.org/docs/about/concepts.html
  • https://kentcdodds.com/blog/implementing-a-simple-state-machine-library-in-javascript
  • https://css-tricks.com/finite-state-machines-with-react/

到了这里,关于探索FSM (有限状态机)应用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity进阶开发-FSM有限状态机

    # Unity进阶开发-FSM有限状态机 我们在进行开发时,到了一定程度上,会遇到数十种状态,继续使用Unity的Animator控制器会出现大量的bool,float类型的变量,而这些错综复杂的变量与Animatator控制器如同迷宫版连线相结合会变得极其的复杂且无法良好维护扩展,出现一个BUG会导致

    2024年02月08日
    浏览(44)
  • 袋鼠云数栈前端从 Multirepo 到 Monorepo 研发效率提升探索之路

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。 本文作者:星野 前端代码管理一直是困扰着不少前端开发团队的难题,从开发到发布的整体工作流程中,除了常规的技术问题外,往往

    2024年02月04日
    浏览(45)
  • Go中的有限状态机FSM的详细介绍

    1.1 有限状态机的定义 有限状态机(Finite State Machine,FSM)是一种数学模型,用于描述系统在不同状态下的行为和转移条件。 状态机有三个组成部分: 状态(State)、事件(Event)、动作(Action) ,事件(转移条件)触发状态的转移和动作的执行。动作的执行不是必须的,可

    2023年04月24日
    浏览(34)
  • 如何基于FSM有限状态机实现Enemies AI

    本文简单介绍如何基于FSM有限状态机实现Enemies AI,首先定义敌人的AI逻辑:默认状态下Enemy为巡逻状态,有若干巡逻点位,Enemy在这些点位之间来回巡逻走动,同时检测Player的位置,当Player进入一定范围内时,Enemy进入寻路状态,寻路到Player位置前,进入Attacking攻击状态,当

    2023年04月09日
    浏览(38)
  • Go中的有限状态机FSM的详细介绍 _

    1、FSM简介 1.1 有限状态机的定义 有限状态机(Finite State Machine,FSM)是一种数学模型,用于描述系统在不同状态下的行为和转移条件。 状态机有三个组成部分: 状态(State)、事件(Event)、动作(Action) ,事件(转移条件)触发状态的转移和动作的执行。动作的执行不是必

    2024年02月12日
    浏览(69)
  • Unity中的AI算法和实现2-有限状态机FSM(上)

    在上一篇文章中, 我们基于 Waypoint 构建了一个最简单的AI怪物, 这个怪物可以在几个点之间巡逻. 本篇文章会在此基础之上, 添加怪物在巡逻过程中发现玩家并追逐玩家, 并且在距离玩家一定距离之后脱离追逐然后继续进行巡逻. 在添加两个状态之前, 我们先介绍什么是 有限状态

    2024年02月01日
    浏览(41)
  • 袋鼠云数栈产品中 AI+ 实现原理剖析

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。 本文作者:修能 生产力工具 + AI 是不可逆转的趋势,慢慢的大模型能力通过 AI Agent 落地的工程化能力也开始趋于成熟。作为大数据产

    2024年01月25日
    浏览(38)
  • 揭秘|来看看袋鼠云数栈内部的资产血缘方案设计与实现

    数据资产现在需要接入数栈内部相关应用的时候,支持查看血缘的类型从表、离线任务增加到需要表、离线任务、实时任务、API任务、指标、标签等,需要支持数栈现有的所有应用任务,最终实现在数据资产平台查看任务的完整应用链路。 虽然增加不同的任务,现阶段资产实

    2024年02月16日
    浏览(39)
  • 袋鼠云产品功能更新报告05期|应有尽“优”,数栈一大波功能优化升级!

    这段时间,我们对产品本身以及客户反馈的一些问题进行了持续的更新和优化,包括对离线平台数据同步功能的更新,数据资产平台血缘问题的优化等,力求满足不同行业用户的更多需求,为用户带来极致的产品使用体验。 以下为袋鼠云产品功能更新报告第五期内容,更多探

    2024年02月04日
    浏览(49)
  • 性能提升30%!袋鼠云数栈基于 Apache Hudi 的性能优化实战解析

    Apache Hudi 是一款开源的数据湖解决方案,它能够帮助企业更好地管理和分析海量数据,支持高效的数据更新和查询。并提供多种数据压缩和存储格式以及索引功能,从而为企业数据仓库实践提供更加灵活和高效的数据处理方式。 在金融领域,企业可以使用 Hudi 来处理大量需要

    2024年02月09日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包