前言
在这里需要提前声明的是,并不是swicth--case和if---else if等代码结构不好。在一般情况下(纯属个人能接受的范围),在1~5个的情况下,使用上述的结构,还是可以接受的,而且代码维护起来,也不用那么费劲。但是如果超过5个以上的分支,个人就不是很建议还是使用这种结构来处理代码了,因为代码不仅难看,而且这么一大坨代码,维护起来真是心里MMP。
那么我们该如何来重构这部分的代码?
先来个示例代码,就是需要多种分支那种,就好比要做一个计算器,输入两个数的值,然后进行加、减、乘、除、平方、立方、开方等等的运算操作。
先来个恶心的代码示例:
#include
//使用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
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);
}
运行结果:
对比这两个版本的代码:
版本一:如果想要增加功能,只能在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的装饰器和闭包函数是什么玩意???自己百度百度哈~~我就不误人子弟了。
如果这篇文章对你有帮助,就点个赞再走吧~~~哈哈哈~~~~