四时宝库

程序员的知识宝库

设计模式之状态模式(设计模式之状态模式 c语言)

介绍:

状态模式是一种行为模式,它与有限状态机的概念紧密相关;其主要思想是程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个状态切换到另一个状态。 不过, 根据当前状态, 程序可能会切换到另外一种状态, 也可能会保持当前状态不变。 这些数量有限且预先定义的状态切换规则被称为转移


作用:

将业务模型抽象成一个有限状态机,减少大量的switch-caseif-else的使用,使得代码逻辑清晰,结构规整;


类比:

智能手机的按键和开关会根据设备当前状态完成不同行为:

  • 当手机处于解锁状态时, 按下按键将执行各种功能。
  • 当手机处于锁定状态时, 按下任何按键都将解锁屏幕。
  • 当手机电量不足时, 按下任何按键都将显示充电页面。

以BLE链路层状态机为例:

#include <stdio.h>
#include <assert.h>
#include <stdbool.h>

/*链路层状态*/
typedef enum
{
    SCAN,
    STANDBY,
    ADV,
    CONN,
    INIT,
}SM_STATE;

/*触发事件*/
typedef enum
{
    EVENT1,
    EVENT2,
    EVENT3,
    EVENT4,
    EVENT5,
    EVENT6,
    EVENT7,
    EVENT8,
    EVENT9,
}SM_EVENT;

/*回调*/
typedef void (*state_cb)(void);

/*状态表*/
typedef struct
{
    SM_EVENT event;
    SM_STATE cur_state;
    SM_STATE next_state;
    state_cb cb;
}SM_TABLE_T;

/*就绪态*/
static void standby_state(void)
{
    printf("Standby\r\n");
}

/*扫描态*/
static void scan_state(void)
{
    printf("Scan\r\n");
}

/*广播态*/
static void adv_state(void)
{
    printf("Adv\r\n");
}

/*连接态*/
static void conn_state(void)
{
    printf("Conn\r\n");
}

/*发起态*/
static void init_state(void)
{
    printf("Init\r\n");
}

/*状态表*/
SM_TABLE_T state_table[] =
{
    {EVENT1, STANDBY, SCAN, scan_state},
    {EVENT2, STANDBY, ADV, adv_state},
    {EVENT3, STANDBY, INIT, init_state},
    
    {EVENT4, SCAN, STANDBY, standby_state},
    {EVENT5, INIT, STANDBY, standby_state},
    {EVENT6, ADV, STANDBY, standby_state},
    {EVENT7, CONN, STANDBY, standby_state},

    {EVENT8 , ADV, CONN, conn_state},
    {EVENT9, INIT, CONN, conn_state},
};


/*状态机*/
typedef struct
{
    SM_STATE cur_state;
    SM_TABLE_T* table;
    int size;
}SM_T;

/*事件处理及状态切换*/
void event_handle(SM_EVENT event, SM_T* sm)
{
    assert(sm != NULL && sm->table != NULL);

    bool find_flag = false;
    for (unsigned char i = 0; i < sm->size; i++)
    {
        if(sm->table[i].event == event && sm->table[i].cur_state == sm->cur_state)
        {
            sm->cur_state = sm->table[i].next_state;
            sm->table[i].cb();
            find_flag = true;
            break;
        }
    }

    if(!find_flag)
    {
        printf("Event wrong!\r\n");
    }
}

void main(void)
{
    SM_T state_machine = {.cur_state = STANDBY, .table = state_table, .size = (sizeof(state_table) / sizeof(SM_TABLE_T))};

    printf("Init to READY\r\n");

    SM_EVENT input_event[] = {EVENT1, EVENT4, EVENT3, EVENT9, EVENT7, EVENT6, EVENT8};

    for (char i = 0; i < sizeof(input_event) / sizeof(SM_EVENT); i++)
    {
        event_handle(input_event[i], &state_machine);
    }
}

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接