读书人

优化if else 跟 switch case 结构

发布时间: 2012-09-01 09:33:03 作者: rapoo

优化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?
  1. int GetMonthDays(int iMonth)
  2. {
  3. int iDays;
  4. if(1== iMonth) {iDays =31;}
  5. else if(2 == iMonth) {iDays =28;}
  6. else if(3 == iMonth) {iDays =31;}
  7. else if(4 == iMonth) {iDays =30;}
  8. else if(5 == iMonth) {iDays =31;}
  9. else if(6 == iMonth) {iDays =30;}
  10. else if(7 == iMonth) {iDays =31;}
  11. else if(8 == iMonth) {iDays =31;}
  12. else if(9 == iMonth) {iDays =30;}
  13. else if(10 == iMonth) {iDays =31;}
  14. else if(11 == iMonth) {iDays =30;}
  15. else if(12 == iMonth) {iDays =31;}
  16. return iDays;
  17. }

上述代码显的就比较笨拙了,代码比较冗长,可读性也比较低。

表驱动方法(C++):

[cpp] view plaincopyprint?
  1. static int s_nMonthdays[12]={31,28,31,30,31,30,31,31,30,31,30,31};
  2. int GetMonthDays(int iMonth)
  3. {
  4. return s_nMonDays[(iMonth - 1)];
  5. }


也许你会有疑问,还是if-esle比较顺手啊,但对于十分冗长的switch-case或if-else最好还是能想办法将其化解开,方法有很多种:

选择函数封装?选择宏?还是选择表驱动?

带着疑问我们还是用例子进行说明比较妥帖些。

1.switch - case (分支越多可读性就越差,维护起来也很麻烦)

[cpp] view plaincopyprint?
  1. #define UN_DEFINED 0
  2. #define PROCESSA 1
  3. #define PROCESSB 2
  4. #define PROCESSC 3
  5. #define PROCESSD 4
  6. int ProcessControl(UINT function_no, void* para_in, void* para_out)
  7. {
  8. int result;
  9. switch(function_no)
  10. {
  11. case PROCESSA:
  12. return = ProcessA(para_in,para_out);
  13. break;
  14. case PROCESSB:
  15. return = ProcessB(para_in,para_out);
  16. break;
  17. case PROCESSC:
  18. return = ProcessC(para_in,para_out);
  19. break;
  20. // 此处省略很多 case 标签
  21. default:
  22. result = UN_DEFINED;
  23. break;
  24. }
  25. return result;
  26. }

[cpp] view plaincopyprint?
  1. int ProcessA(void* para_in, void* para_out)
  2. {
  3. // code here
  4. }
  5. int ProcessB(void* para_in, void* para_out)
  6. {
  7. // code here
  8. }
  9. int ProcessC(void* para_in, void* para_out)
  10. {
  11. // code here
  12. }
  13. // other similar function

2 宏定义版本

[cpp] view plaincopyprint?
  1. #define DISPATCH_BEGIN(func) switch(func) \
  2. {
  3. #define DISPATCH_FUNCTION(func_c,function) case func_c: \
  4. result = function(para_in,para_out);\
  5. break;
  6. #define DISPATCH_END(code) default: \
  7. result = code; \
  8. }
  9. // PROCESSA processA 等定义同例1
  10. int ProcessControl(UINT function_no, void* para_in, void* para_out)
  11. {
  12. int result;
  13. DISPATCH_BEGIN(function_no)
  14. DISPATCH_FUNCTION(PROCESSA,processA)
  15. DISPATCH_FUNCTION(PROCESSB,processB)
  16. DISPATCH_FUNCTION(PROCESSC,processC)
  17. // omit many similar things
  18. DISPATCH_BEGIN(UN_DEFINED)
  19. return result;
  20. }
这个版本,稍稍有点感觉,但是这种方法治标不治本。还是看看表驱动如何实现的吧 。

3 表驱动(数组版本)

[cpp] view plaincopyprint?
  1. typedef struct tagDispathItem
  2. {
  3. UINT function_no;
  4. ProcessFuncPtr func_ptr;
  5. }DISPATCH_ITEM;
  6. DISPATCH_ITEM dispatch_table(MAX_DISPATCH_ITEM);
  7. int ProcessControl(UINT function_no, void* para_in, void* para_out)
  8. {
  9. int i;
  10. for(i = 0;i<MAX_DISPATCH_ITEM;++i)
  11. {
  12. if(function_no == dispatch_table[i].func_no)
  13. {
  14. return dispatch_table[i].funcptr(para_in,para_out);
  15. }
  16. }
  17. return UN_DEFINED;
  18. }

4.表驱动(高级数据结构)

[cpp] view plaincopyprint?
  1. typedef std::hash_map<UINT,ProcessFuncPtr> CmdHandlerMap;
  2. CmdHandlerMap HandlerMap;
  3. void InitHandlerMap()
  4. {
  5. HandlerMap[PROCESSA]=processFuncPtr(&ProcessA);
  6. HandlerMap[PROCESSB]=processFuncPtr(&ProcessB);
  7. HandlerMap[PROCESSC]=processFuncPtr(&ProcessC);
  8. // omit other many similar code
  9. }
  10. int ProcessControl(UINT function_no, void* para_in, void* para_out)
  11. {
  12. CmdHandlerMap::iterator it = HandlerMap.Find(function_no);
  13. if(it != HandlerMap.end())
  14. {
  15. ProcessFuncPtr pHandler = it->second;
  16. return (*pHandler)(para_in,para_out);
  17. }
  18. return UN_DEFINED;
  19. }

由此看来,表驱动的好处就是ProcessControl的代码就几行,逻辑不会改变。如添加新功能的时候,只要维护dispatch_table或HandlerMap就可以了。

到此你终于可以和switch-case 和 if-else 说 good-bye。


读书人网 >软件架构设计

热点推荐