嵌入式开发中常用的软件设计模式(c语言实现)

软件项目各有不同,开发语言多种多样,但软件开发这种行为过程,有其规律性,很多前辈从各个角度对软件开发这种行为做了总结。我们这里来介绍GOF从工程实现的角度总结的23种设计模式(最近实践),这将会是一个系列。

软件开发是一种智力活动,沟通交流时多有障碍,从设计模式的角度来沟通功能的实现,也能大大提高沟通效率。

在我个人的软件开发经历中,感受最深的是命令模式和观察者模式。我们先从命令模式开始。

先来看一个通讯协议相关的例子,数据帧定义如下:

帧长度 传感器类型 数据
1字节 1字节 n字节

传感器数据格式定义如下

传感器 类型号 数据格式
温度传感器 整型数据(4字节)
湿度传感器 整型数据(4字节)

解析实现可如下实现:

static int parse(const char *data,size_t n)
{
    int len = data[0];
    int type = data[2];
    int value;
    switch(type){
        case 1:
            value = *(int *)&data[3];
            printf("temperatue = %d\n",value);
        case 2:
            value = *(int *)&data[3];
            printf("humidity = %d\n",value);
        default:
            printf("parse error\n");
    }
    
}

相信你已经嗅到了这段代码的坏味道,如果我们系统中要添加更多的传感器类型,势必需要向switch case 语句中增加更多的case 语句。使得parse函数越来越臃肿。

当然,我们可以采用,如下方式规避一些问题

static int parse_temperature(const char *data,size_t len)
{
    assert(len == 4);
    int value = *(int *)data;
    printf("temperature = %d\n",value);
}
static int parse_humidity(const char *data,size_t len)
{
    assert(len==4);
    int value = *(int *)data;
    printf("humidity = %d\n",value);
}

static void parse(const char *data,size_t len)
{
    int data_len = data[0];
    int data_type = data[1];
    switch(type){
        case 1:
            parse_temperature(data+2,data_len-2);
            break;
        case 2:
            parse_humidity(data+2,data_len-2);
            break;
        default:
            break;
    }
}

上面的代码相比与第一次实现有所改善,但是我们采用命令模式实现后,会看到,无论是可读性,可扩展性,都会得到相当成都的提高。

typedef int (*parse_func)(const char *data,size_t len);

struct parse_handler{
    int type;
    parse_func func;
}

static int parse_temperature(const char *data,size_t len)
{
    assert(len == 4);
    int value = *(int *)data;
    printf("temperature = %d\n",value);
}
static int parse_humidity(const char *data,size_t len)
{
    assert(len==4);
    int value = *(int *)data;
    printf("humidity = %d\n",value);
}

static struct parse_handler handlers = {
    {1,parse_tmepeature},
    {2,parse_humidity},
};

#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
static parse_func parse_func_find(int type)
{
    int i;
    for(i=0;i

如上,需要增加或者修改传感器的时候,我们只需要关注handlers这个数组。

static struct parse_handler handlers = {
    {1,parse_tmepeature},
    {2,parse_humidity},
};

这样写的优势

  • 传感器类型和解析实现直接写在了同一行,非常直观,也没有必要将传感器类型数据定义为宏。
  • 添加传感器的时候,只要在结构体数组中添加一行即可,如果是第二种实现,则需要在parse函数中,添加一个case语句,若是遗忘了break很容易导致错误。

这种实现方式,基本是此类问题的最优解。被称为命令模式。一个type被称为一个命令,解析函数对应于命令的实现。

很多命令行工具都是采用的此类实现方式。伪代码如下:

char buffer[1024];
while(true){
    char *p = fgets(buffer,sizeof(buffer),stdin);
    execute(p) //执行某个命令,先find再执行。
}

你可能感兴趣的:(嵌入式开发中常用的软件设计模式(c语言实现))