C語言和設計模式(3.2命令模式)

       在命令模式裏面,我們只需要維護一個命令列表就行了,而不需要關注解析函數本身。

// 當心字節對齊的問題
typedef struct {
    uint8_t head;
    uint8_t cmd;
    uint16_t length;
    uint8_t data[1];
} package_t;

static void parse_temperature( uint8_t *buffer )
{
    int value = *buffer;
    printf( "temperature = %d\n", value );
}
static void parse_humidity( uint8_t *buffer )
{
    int value = *buffer;
    printf( "humidity = %d\n", value );
}
static void parse_illumination( uint8_t *buffer )
{
    int value = *buffer;
    printf( "illumination = %d\n", value );
}

typedef struct {
    uint8_t cmd;
    void ( * handle )( uint8_t *buffer );
} package_entry_t;

static const package_entry_t package_items[] = {
    {0x01, parse_temperature},
    {0x02, parse_humidity},
    {0x03, parse_illumination},
    {0xFF, NULL},
};

static uint8_t parse( uint8_t *buffer, uint16_t length )
{
    package_t *frame = ( package_t * )buffer;
    uint8_t tail = buffer[length - 1];
    const package_entry_t *entry;

    if ( frame->head != 0xFF ) {
        return 0;
    }

    for ( entry = package_items; entry->handle != NULL; ++entry ) {
        if ( frame->cmd == entry->cmd ) {
            entry->handle( frame->data );
            break;
        }
    }

    return 1;
}

int main( void )
{
    uint8_t buffer[] = {0xFF, 0x01, 0x00, 0x05, 0x02};
    parse( buffer, 5 );
    uint8_t buffer_2[] = {0xFF, 0x02, 0x00, 0x05, 0x02};
    parse( buffer_2, 5 );
    uint8_t buffer_3[] = {0xFF, 0x03, 0x00, 0x05, 0x02};
    parse( buffer_3, 5 );
}

        我們可以看到,解析函數寫好之後就不用動了,需要變化的只是一個表。這樣寫能讓代碼看起來乾淨整潔清晰,命令也可以使用宏定義或者枚舉,看自己的喜好吧。一個命令對應一個處理函數,儘量使用此類方式去取代swicth case的方式,始終讓代碼保持整潔易擴展易維護的特性。

        上面使用了命令模式作用於串口協議,同樣的方式可以適用於各種協議,網口協議的話,格式都不用改。如果是can協議的話,將can的id用作命令,就ok了。其他的,類似。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章