论如何去掉那些恶心的switch-case和if--else if的代码

前言

     在这里需要提前声明的是,并不是swicth--caseif---else if等代码结构不好。在一般情况下(纯属个人能接受的范围),在1~5个的情况下,使用上述的结构,还是可以接受的,而且代码维护起来,也不用那么费劲。但是如果超过5个以上的分支,个人就不是很建议还是使用这种结构来处理代码了,因为代码不仅难看,而且这么一大坨代码,维护起来真是心里MMP。

    那么我们该如何来重构这部分的代码?

    先来个示例代码,就是需要多种分支那种,就好比要做一个计算器,输入两个数的值,然后进行加、减、乘、除、平方、立方、开方等等的运算操作。

   先来个恶心的代码示例:


#include <stdio.h>

//使用switch-case结构,自己脑补下
double result_get_version1(double num1,double num2,char cal_type)
{
    double ret = 0.0;
    if(cal_type == '+')
    {
        ret = num1 + num2;
    }
    else if(cal_type == '-')
    {
        ret = num1 - num2;
    }
    else if(cal_type == '*')
    {
        ret = num1 * num2;
    }
    else if(cal_type == '/')
    {
        ret = num1 / num2;//这里先不判断除零异常
    }
    else if(cal_type == '2')//这里暂且用2来代表平方运算
    {
        ret = num1 * num1;//简化,num2不起作用
    }
    else if(cal_type == '3')//这里暂且用3代表立方
    {
        ret = num1 * num1 * num1;//简化,num2不起作用
    }
    else
    {
        printf("error cal_type!\r\n");//暂且支持这么多类型的计算,
    }

    return ret;
}

int main(int argc,char *argv[])
{
    double val = 0.0;

    val = result_get_version1(10,20,'+');
    printf("value = %f\r\n",val);
    val = result_get_version1(10,20,'-');
    printf("value = %f\r\n",val);
    val = result_get_version1(10,20,'*');
    printf("value = %f\r\n",val);
    val = result_get_version1(10,20,'/');
    printf("value = %f\r\n",val);
    val = result_get_version1(10,20,'2');
    printf("value = %f\r\n",val);
    val = result_get_version1(10,20,'3');
    printf("value = %f\r\n",val);
}

运行结果如下:

如果,我这里是说如果后面还要支持100种运算的话,那我们是不是要再写100个else if的判断语句?如果你真的是照这样的写法写下去,那么恭喜你了,你中大奖了。有人就反驳了,本来就是要判断这么多条件的,不写这么多分支怎么判断的完?事实上真的是这样吗?实际上我们可以有更好的办法来解决这种分支多的代码。

现在就让我们来重构下代码吧:

#include <stdio.h>


typedef struct CAL_FUNC_MAPPING
{
    char cal_type;
    double (*result_get)(double num1,double num2);
}cal_func_mapping;


double result_get_add(double num1,double num2)
{
    return num1 + num2;
}

double result_get_sub(double num1,double num2)
{
    return num1 - num2;
}

double result_get_mul(double num1,double num2)
{
    return num1 * num2;
}

double result_get_div(double num1,double num2)
{
    return num1 / num2;
}
//暂且表示平方
double result_get_2(double num1,double num2)
{
    return num1 * num1;
}
//暂且表示立方
double result_get_3(double num1,double num2)
{
    return num1 * num1 * num1;
}
//添加其他运算,继续往后添加
//....


static cal_func_mapping cal_func_mapping_table[] =
{
    {
        '+',
        result_get_add
    },
    {
        '-',
        result_get_sub
    },
    {
        '*',
        result_get_mul
    },
    {
        '/',
        result_get_div
    },
    {
        '2',
        result_get_2
    },
    {
        '3',
        result_get_3
    }
    //增加其他运算,继续往后添加
    // ...
};

double result_get_version2(double num1,double num2,char cal_type)
{
    int count = sizeof(cal_func_mapping_table) / sizeof(cal_func_mapping);
    int i = 0;
    double ret = 0.0;

    for(i = 0; i < count; i ++)
    {
        if(cal_func_mapping_table[i].cal_type == cal_type)
        {
            ret = cal_func_mapping_table[i].result_get(num1,num2);
            break;//跳出循环
        }
    }

    if(i == count)
    {
        printf("error cal_type!\r\n");//暂且支持这么多类型的计算,
    }

    return ret;
}

int main(int argc,char *argv[])
{
    double val = 0.0;

    val = result_get_version2(10,20,'+');
    printf("value = %f\r\n",val);
    val = result_get_version2(10,20,'-');
    printf("value = %f\r\n",val);
    val = result_get_version2(10,20,'*');
    printf("value = %f\r\n",val);
    val = result_get_version2(10,20,'/');
    printf("value = %f\r\n",val);
    val = result_get_version2(10,20,'2');
    printf("value = %f\r\n",val);
    val = result_get_version2(10,20,'3');
    printf("value = %f\r\n",val);
}

运行结果:

扫描二维码关注公众号,回复: 10630642 查看本文章

对比这两个版本的代码:

版本一:如果想要增加功能,只能在result_get_version1函数里面增加if-else条件判断,对扩展一点也不友好。

版本二:如果想要增加功能,首先要新增一个运算的计算函数,然后在cal_func_mapping_table表中增加对应的运算即可,根本就不需要修改result_get_version2里面的函数。符合了程序的设计原则:对扩展开发,对修改关闭!

版本二关键设计点:

利用映射的方式进行处理条件分支。

首先:定义一个结构体(具体问题具体分析):

typedef struct CAL_FUNC_MAPPING
{
    char cal_type;//用来匹配输入的运算
    double (*result_get)(double num1,double num2);//回调函数来指向用户写的运算函数
}cal_func_mapping;

其次:定义一个映射表(其实就是一个cal_func_mapping类型的数组了)~~~

static cal_func_mapping cal_func_mapping_table[] =
{
    {
        '+',
        result_get_add
    },
    {
        '-',
        result_get_sub
    },
    {
        '*',
        result_get_mul
    },
    {
        '/',
        result_get_div
    },
    {
        '2',
        result_get_2
    },
    {
        '3',
        result_get_3
    }
};

最后:在实际调用的计算函数来根据计算类型,选择相应的计算函数就OK了

double result_get_version2(double num1,double num2,char cal_type)
{
    int count = sizeof(cal_func_mapping_table) / sizeof(cal_func_mapping);
    int i = 0;
    double ret = 0.0;

    for(i = 0; i < count; i ++)
    {
        if(cal_func_mapping_table[i].cal_type == cal_type)
        {
            ret = cal_func_mapping_table[i].result_get(num1,num2);
            break;//跳出循环
        }
    }

    if(i == count)
    {
        printf("error cal_type!\r\n");//暂且支持这么多类型的计算,
    }

    return ret;
}

PS:如果C语言支持Python的装饰器和闭包函数的话,就只需要增加新的运算计算函数了。至于Python的装饰器和闭包函数是什么玩意???自己百度百度哈~~我就不误人子弟了。

如果这篇文章对你有帮助,就点个赞再走吧~~~哈哈哈~~~~

发布了8 篇原创文章 · 获赞 4 · 访问量 4068

猜你喜欢

转载自blog.csdn.net/u011522841/article/details/105404436