• 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

  • 相关阅读:
    HTTPS原理浅析
    Java8 HashMap源码分析
    Java8 ArrayList源码分析
    Java反射
    Java泛型
    Tensorflow卷积神经网络
    Java8 Stream简介
    java.io与网络通信
    Python实现RNN
    域名系统DNS简介
  • 原文地址:https://www.cnblogs.com/lxjshuju/p/7162232.html
Copyright © 2020-2023  润新知