不要再用if/else和switch/case了,快使用“表驱动法”代替,面向对象思维,对修改关闭。
Posted CodeBowl
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不要再用if/else和switch/case了,快使用“表驱动法”代替,面向对象思维,对修改关闭。相关的知识,希望对你有一定的参考价值。
使用表驱动法,替换复杂的if/else和switch/case语句。
复杂的if/else
忘记从哪里看到这么一段话:
互斥条件表驱动
嵌套条件校验链
短路条件早return
零散条件可组合
在实际编程中,我已经遇到了第一种情况了,就是过多的条件导致的分支。在之前我都会用switch/case代替这种情况,毕竟这就是switch的作用,但是这并不是最优解,因为当条件逐渐复杂到几百条的时候,每次修改都是一种痛苦,过长的代码阅读起来也不方便,并且不满足“面向对象”的思想:对修改关闭,对扩展开放。
所以这时候就需要用到了表驱动法!
表驱动法
表驱动法是什么
表驱动是一种编程模式,是一种将输入变量作为索引在表里查找直接的结果或者处理函数,而不是用很多的逻辑语句来进行判断(比如if-sle||switch_case).索引表可以是个数组、map或者其他高效率查找的数据结构。
举个例子
switch(weeek)
case Monday:
Console.WritleLine("星期一");
case Tuesday:
Console.WritleLine("星期二");
case Wednesday:
Console.WritleLine("星期三");
case Thursday:
Console.WritleLine("星期四");
case Friday:
Console.WritleLine("星期五");
case Saturday:
Console.WritleLine("星期六");
case Sunday:
Console.WritleLine("星期日");
这段case语句代码实现的功能是将星期的英文转化为中文输出,幸亏一周只有七天,若有八天、九天还需要进行代码的增加,想想都特别麻烦。当使用表驱动法时,你就能发现当遇到此类时会变得特别方便。
解决方法:
1、case语句或if-else语句的结果返回结果是某个值
其实上述的例子就属于这类情况,表驱动法解决过程是:首先将所有返回的值写进一个数组中,定义数组weekDay
string weekDay[]="星期一","星期二","星期三","星期四","星期五","星期六","星期日"
然后要解决的是将case值和数组下标索引能联系起来,这里最好的办法就是使用枚举型,这是因为枚举值是可以转化为数字的,定义一个枚举Week
public enum Week
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
(int)Week.Monday的值是1,如此就解决了将case值和数组下标之间转换的问题。所以上例通过表驱动法来实现就只需要一行代码就可以了:
week=weekDay.Monday;//week为WeekDay中任意一个枚举值,这里设为Monday
string result=weekDay[(int)week];
Console.Writle(result);
实战来了
下面通过加减乘除来实现一个简易计算器,先用未优化的switch-case来实现:
#include <iostream>
#include <time.h>
int add(int a, int b)
return a + b;
int subtraction(int a, int b)
return a - b;
int multiplication(int a, int b)
return a * b;
int division(int a, int b)
assert(b != 0);
return a / b;
int Calculator(char symbol, int a, int b)
int ans = 0;
switch (symbol)
case ' + ':
ans = add(a, b);
break;
case ' - ':
ans = subtraction(a, b);
break;
case ' * ':
ans = multiplication(a, b);
break;
case ' / ':
ans = division(a, b);
break;
default:
std::cout << "wrong symbol" << std::endl;
break;
return ans;
int main()
int res = 0;
clock_t startTimes = clock();
// 一加一减,防止结果溢出
for (int i = 0; i < 1000000; ++i)
res = Calculator('+', res, i);
res = Calculator('-', res, i);
clock_t endTimes = clock();
std::cout << "switch cost times : " << (endTimes -startTimes)/ CLOCKS_PER_SEC << "ms." << std::endl;
getchar();
return 0;
接着,我们使用表驱动方式来做优化:
#include <iostream>
#include <time.h>
#include <map>
int add(int a, int b)
return a + b;
int subtraction(int a, int b)
return a - b;
int multiplication(int a, int b)
return a * b;
int division(int a, int b)
assert(b != 0);
return a / b;
// 定义函数指针
using func = int (*)(int, int);
int main()
int res = 0;
// 这里也可以用map来代替函数指针数组,但是小数据量上实际效果可能还没switch-case快
func table[4];
table['+'] = &add;
table['-'] = &subtraction;
table['*'] = &multiplication;
table['/'] = &division;
clock_t startTimes = clock();
for (int i = 0; i < 1000000; ++i)
res = table['+'](res, i);
res = table['-'](res, i);
clock_t endTimes = clock();
std::cout << "arrary table cost times : " << (endTimes - startTimes) / CLOCKS_PER_SEC << "ms." << std::endl;
getchar();
return 0;
总结
表驱动方式代码量少,逻辑清晰,更符合设计模式思想,方便函数增添或者删除。但是在c++里需要用到函数指针、指针数组,对新手不友好。但是如果采用合理的索引表,在数据量较大的情况下可以有效提升程序运行速度。
参考资料
https://blog.csdn.net/qq525003138/article/details/121374565
http://www.cppcns.com/ruanjian/c/418836.html
我有N种方法消除 if-else,而你却无可奈何(第二篇:表驱动编程方法)
以上是关于不要再用if/else和switch/case了,快使用“表驱动法”代替,面向对象思维,对修改关闭。的主要内容,如果未能解决你的问题,请参考以下文章
if...else与switch...case的执行效率问题
switch...case 与 if...else 的性能分析