• 状态机


    参考https://blog.csdn.net/u012841414/article/details/123903539

    简单状态机

    通过switch(state)完成。

    void onEvent(EventCode ec)
    {
      switch (state)
      {
      case ST_IDLE:
            if(EV_PLAY_PAUSE == ec)
              startPlayer();
            break;
      case ST_PLAY:
            if(EV_STOP == ec)
              stopPlayer();
            else if(EV_PLAY_PAUSE == ec)
              pausePlayer();
            break;
      case ST_PAUSE:
            if(EV_STOP == ec)
              stopPlayer();
            else if(EV_PLAY_PAUSE == ec)
              resumePlayer();
            break;
      default:
            break;
      }
    }

    这样会导致一个问题,当状态和事件增加后,onEvent函数就会变得非常庞大,这是因为该函数的代码行数与状态和事件数量的乘积成正比,直接导致代码行数爆炸增长,代码会越发变得难以阅读和维护。

    比如新增一个事件,强制关闭播放器。显然任何状态下都能强制关闭,那么case里面,就要多三个if判断。

    比如新增一个状态,高音播放态,那么对应的也要增加一个事件。每个case要多一个if判断,并且新增一个case。高音播放态显然能够从到达暂停、停止、正常播放态。于是新增的case有三个if判断。可以看到,我们新增一个内容,就要改变简单状态机几乎所有的代码。

    状态模式(状态机)

    我们可以利用c语言的多态特性来分解复杂的条件分支(关于c语言多态的实现,请查看c语言面向对象基础)。这样一来可以就避免大量的swith...case和 if...else等条件分支语句,提高程序的可维护性和可扩展性。

    初始化:pCurrentState 

    四步定义法:定义顶层接口,定义状态,定义状态转移方法,定义顶层按钮方法(播放和暂停按钮往往是同一个)

    定义顶层接口

    typedef struct State{
      void (* stop)();
      void (* palyOrPause)();
    }State;

    总的来说,就是以状态为对象,在状态中定义状态转移的方法。比如播放态

    State PLAY = {
      stopPlay,
      pausePlay
    };

    State IDLE = {
      ignore,//空闲状态时,stop键操作无效,play/pause会开始播放音乐
      startPlay
    };

    我们定义了两个状态转移的方法

    void startPlay()
    {
      //实现具体功能
      printf("开始播放音乐\n");
      //进入播放状态
      pCurrentState = &PLAY;
    }

    状态转移方法主要是改变当前状态pCurrentState 

    顶层按钮方法

    State context = {
      onStop,
      onPlayOrPause
    };
     
    void onStop(State *pThis)
    {
      pCurrentState->stop(pThis);
    }
     
    void onPlayOrPause(State *pThis)
    {
      pCurrentState->palyOrPause(pThis);
    }

    测试

    void main()
    {
      init();
      context.palyOrPause();//播放
      context.palyOrPause();//暂停
      context.palyOrPause();//播放
      context.stop();//停止
    }
  • 相关阅读:
    Tomcat 配置用户认证服务供C#客户端调用
    Solr与HBase架构设计
    一个自定义MVP .net框架 AngelFrame
    Dell R720上的系统安装问题的解决办法(关于RAID建立磁盘阵列的技术)
    中文分词器性能比较
    关于RabbitMQ关键性问题的总结
    js基本类型与引用类型,浅拷贝和深拷贝
    sass初学入门笔记(一)
    Emmet插件比较实用常用的写法
    今天发现新大陆:haml和Emmet
  • 原文地址:https://www.cnblogs.com/MiraculousB/p/16619238.html
Copyright © 2020-2023  润新知