zoukankan      html  css  js  c++  java
  • C/C++用状态转移表联合函数指针数组实现状态机FSM

    状态机在project中使用很的频繁,有例如以下常见的三种实现方法:
    1. switch-case 实现。适合简单的状态机。
    2. 二维状态表state-event实现。逻辑清晰。可是矩阵通常比較稀疏,并且维护麻烦。
    3. 用状态转移表stateTransfer Table实现,数组大小等于状体转移边个数,易扩展;
    以下用一个样例来进行具体说明,描写叙述的例如以下场景:

    描写叙述对象:门
    状态:开着、关着、锁着 (这里的关着指关了但未锁的状态)
    事件:开门、关门、上锁、解锁

    代码实现用枚举来定义状态和事件,操作数据节点转移到目的状态用函数实现。枚举本身默认是从0開始的int类型,利用这个特点将状态转移函数放到函数指针数组中与状态相应起来。方便操作。
    核心数据结构例如以下:

    状态:枚举类型
    事件:枚举类型
    状态转移结构体:{当前状态、事件、下个状态},定义一个全局数组来使用
    状态变更函数:到下个状态(放到数组中与状态枚举相应起来)

    此种实现方法easy扩展,添加状态和事件都比較easy。

    假设存在一个状态通过相应事件能够转移到多个状态的情形,则能够扩展状态转移函数。或者在状态转移结构中添加一个推断函数字段。
    代码实现例如以下:

    #include <iostream>
    using namespace std;
    
    typedef enum{
        OPENED,
        CLOSED,
        LOCKED,
    }  State;
    
    typedef enum{
        OPEN,
        CLOSE,
        LOCK,
        UNLOCK
    } Event;
    
    typedef struct{
        State currentState;
        Event event;
        State NextState;
    } StateTransfer;
    
    typedef struct{
        State state;
        int transferTimes;
    }Door;
    
    StateTransfer g_stateTransferTable[]{
        {OPENED, CLOSE,  CLOSED},
        {CLOSED, OPEN,   OPENED},
        {CLOSED, LOCK,   LOCKED},
        {LOCKED, UNLOCK, CLOSED},
    };
    
    void toOpen(Door& door);
    void toClose(Door& door);
    void toLock(Door& door);
    typedef void (*pfToState)(Door& door);
    pfToState g_pFun[] = {toOpen, toClose, toLock}; //状态枚举值相应下标
    
    void toOpen(Door& door){
        door.state = OPENED;
        cout << "open the door!
    ";
    }
    
    void toClose(Door& door){
        door.state = CLOSED;
        cout << "close the door!
    ";
    }
    
    void toLock(Door& door){
        door.state = LOCKED;
        cout << "lock the door!
    ";
    }
    
    void transfer(Door& door,const Event event){
        for (int i = 0; i < sizeof(g_stateTransferTable)/sizeof(StateTransfer); ++i) {
            if(door.state == g_stateTransferTable[i].currentState &&
               event == g_stateTransferTable[i].event){
                g_pFun[g_stateTransferTable[i].NextState](door);
                door.transferTimes++;
                cout << "transfer ok!
    ";
                return;
            }
        }
        cout << "This event cannot transfer current state!!
    ";
        return;
    }
    
    void printDoor(const Door& door){
        string stateNote[] = {"opened","closed","locked"}; // 下标正好相应状态枚举值
        cout << "the door's state is: " << stateNote[door.state] << endl;
        cout << "the door transfer times is: " << door.transferTimes << endl;
    }
    
    int main(){
        Door door = {CLOSED, 0};
        printDoor(door);
        transfer(door, OPEN);
        printDoor(door);
        transfer(door, LOCK);
        printDoor(door);
        transfer(door, CLOSE);
        printDoor(door);
        return 0;
    }

    执行结果例如以下:

    the door’s state is: closed
    the door transfer times is: 0
    open the door!
    transfer ok!
    the door’s state is: opened
    the door transfer times is: 1
    This event cannot transfer current state!!
    the door’s state is: opened
    the door transfer times is: 1
    close the door!
    transfer ok!
    the door’s state is: closed
    the door transfer times is: 2

  • 相关阅读:
    父子进程 signal 出现 Interrupted system call 问题
    一个测试文章
    《淘宝客户端 for Android》项目实战 html webkit android css3
    Django 中的 ForeignKey ContentType GenericForeignKey 对应的数据库结构
    coreseek 出现段错误和Unigram dictionary load Error 新情况(Gentoo)
    一个 PAM dbus 例子
    漫画统计学 T分数
    解决 paramiko 安装问题 Unable to find vcvarsall.bat
    20141202
    js
  • 原文地址:https://www.cnblogs.com/lxjshuju/p/7162232.html
Copyright © 2011-2022 走看看