优化if else 跟 switch case 结构
优化if else 和 switch case 结构简单:if -else 和switch-case 是我们经常见到的一个普通编程技术。他们所
优化if else 和 switch case 结构
简单:
if -else 和switch-case 是我们经常见到的一个普通编程技术。他们所生成的代码按照顺序进行比较,如果发现匹配,程序就会跳转到满足条件的语句上执行。
优化建议1:
按照他们发生的相对频率来进行排序,把最可能发生的情况放在第一位,最不可能的情况放在最后一位。
另外如过case 语句比较多,为了减少比较次数,建议把switch转化为嵌套的switch语句。即把频率高的的case,放在一个switch中,并且是switch语句的最外层,把频率低的case放在另外一个switch中。
复杂:
如果这种判断逻辑很多,很显然不易于维护和阅读,推荐使用“表驱动”的方法。
表驱动法(Table driven method),市一中不必用很多的逻辑语句就可以把表中的信息找出来的方法。它市一中设计模式,可以用来代替复杂的if-else 和switch-case逻辑判断。从某种意义上说,任何信息都可以通过“表”来进行选择。
在表相对简单的情况下,逻辑语句往往更简单,更直接。但随着逻辑链的复杂,表就变的越来越富有吸引力了。
初始表驱动:
例子:求每月的天数(不考虑闰年的情况,这个不是我们关注的重点)
一般的代码(C++):
[cpp] view plaincopyprint?
- int GetMonthDays(int iMonth)
- {
- int iDays;
- if(1== iMonth) {iDays =31;}
- else if(2 == iMonth) {iDays =28;}
- else if(3 == iMonth) {iDays =31;}
- else if(4 == iMonth) {iDays =30;}
- else if(5 == iMonth) {iDays =31;}
- else if(6 == iMonth) {iDays =30;}
- else if(7 == iMonth) {iDays =31;}
- else if(8 == iMonth) {iDays =31;}
- else if(9 == iMonth) {iDays =30;}
- else if(10 == iMonth) {iDays =31;}
- else if(11 == iMonth) {iDays =30;}
- else if(12 == iMonth) {iDays =31;}
- return iDays;
- }
上述代码显的就比较笨拙了,代码比较冗长,可读性也比较低。
表驱动方法(C++):
[cpp] view plaincopyprint?
- static int s_nMonthdays[12]={31,28,31,30,31,30,31,31,30,31,30,31};
- int GetMonthDays(int iMonth)
- {
- return s_nMonDays[(iMonth - 1)];
- }
也许你会有疑问,还是if-esle比较顺手啊,但对于十分冗长的switch-case或if-else最好还是能想办法将其化解开,方法有很多种:
选择函数封装?选择宏?还是选择表驱动?
带着疑问我们还是用例子进行说明比较妥帖些。
1.switch - case (分支越多可读性就越差,维护起来也很麻烦)
[cpp] view plaincopyprint?
- #define UN_DEFINED 0
- #define PROCESSA 1
- #define PROCESSB 2
- #define PROCESSC 3
- #define PROCESSD 4
-
-
-
- int ProcessControl(UINT function_no, void* para_in, void* para_out)
- {
- int result;
- switch(function_no)
- {
- case PROCESSA:
- return = ProcessA(para_in,para_out);
- break;
- case PROCESSB:
- return = ProcessB(para_in,para_out);
- break;
- case PROCESSC:
- return = ProcessC(para_in,para_out);
- break;
- // 此处省略很多 case 标签
-
- default:
- result = UN_DEFINED;
- break;
- }
- return result;
- }
[cpp] view plaincopyprint?
- int ProcessA(void* para_in, void* para_out)
- {
- // code here
- }
- int ProcessB(void* para_in, void* para_out)
- {
- // code here
- }
- int ProcessC(void* para_in, void* para_out)
- {
- // code here
- }
-
- // other similar function
2 宏定义版本
[cpp] view plaincopyprint?
- #define DISPATCH_BEGIN(func) switch(func) \
- {
-
- #define DISPATCH_FUNCTION(func_c,function) case func_c: \
- result = function(para_in,para_out);\
- break;
-
- #define DISPATCH_END(code) default: \
- result = code; \
- }
-
- // PROCESSA processA 等定义同例1
- int ProcessControl(UINT function_no, void* para_in, void* para_out)
- {
- int result;
- DISPATCH_BEGIN(function_no)
- DISPATCH_FUNCTION(PROCESSA,processA)
- DISPATCH_FUNCTION(PROCESSB,processB)
- DISPATCH_FUNCTION(PROCESSC,processC)
- // omit many similar things
-
- DISPATCH_BEGIN(UN_DEFINED)
- return result;
- }
-
这个版本,稍稍有点感觉,但是这种方法治标不治本。还是看看表驱动如何实现的吧 。
3 表驱动(数组版本)
[cpp] view plaincopyprint?
- typedef struct tagDispathItem
- {
- UINT function_no;
- ProcessFuncPtr func_ptr;
- }DISPATCH_ITEM;
- DISPATCH_ITEM dispatch_table(MAX_DISPATCH_ITEM);
-
- int ProcessControl(UINT function_no, void* para_in, void* para_out)
- {
- int i;
- for(i = 0;i<MAX_DISPATCH_ITEM;++i)
- {
- if(function_no == dispatch_table[i].func_no)
- {
- return dispatch_table[i].funcptr(para_in,para_out);
- }
- }
- return UN_DEFINED;
- }
4.表驱动(高级数据结构)
[cpp] view plaincopyprint?
- typedef std::hash_map<UINT,ProcessFuncPtr> CmdHandlerMap;
- CmdHandlerMap HandlerMap;
-
- void InitHandlerMap()
- {
- HandlerMap[PROCESSA]=processFuncPtr(&ProcessA);
- HandlerMap[PROCESSB]=processFuncPtr(&ProcessB);
- HandlerMap[PROCESSC]=processFuncPtr(&ProcessC);
- // omit other many similar code
- }
-
- int ProcessControl(UINT function_no, void* para_in, void* para_out)
- {
- CmdHandlerMap::iterator it = HandlerMap.Find(function_no);
- if(it != HandlerMap.end())
- {
- ProcessFuncPtr pHandler = it->second;
- return (*pHandler)(para_in,para_out);
- }
- return UN_DEFINED;
- }
由此看来,表驱动的好处就是ProcessControl的代码就几行,逻辑不会改变。如添加新功能的时候,只要维护dispatch_table或HandlerMap就可以了。
到此你终于可以和switch-case 和 if-else 说 good-bye。