频道澳门葡京手机版网址
登录注册
澳门葡京手机版网址 > 澳门葡京手机版网址 > App开发 > 其他 > 正文
提高C++代码质量 - 用表驱动取代冗长的逻辑选择
2018-08-15 11:19:29      个评论      
收藏   我要投稿

概述:用表驱动替代冗长的逻辑语句,遵循元编程思想。

表驱动法(Table driven method),是一种设计模式,可以用来代替复杂的if/else或switch-case逻辑判断。

假设要设计一个函数,该函数的功能是获得每个月的天数,如下:

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;

}

本来应该是一件很简单的事情,代码却这么冗余,同时这也导致了代码可读性的降低。更好的方法是使用表驱动,如下:

static int s_nMonthDays[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int GetMonthDays(int iMonth)

{

return s_nMonthDays[iMonth - 1];

}

可以明显看出,用了一些存储空间作为代价,代码清晰了很多,效率也提升了。

那么,表驱动方法为什么优于“函数封装或宏”?

简短的switch-case或if/else用起来还是比较顺手的,所以还是继续用吧。但是对于分支太多的,最好想办法将其化解开。

化解长switch-case的方法有很多,是选择函数封装、宏,还是表驱动?看下面的示例:

//版本1 – case分支版

int ProcessControl(UINT function_no, void* para_in, void* para_out)

{

int result;

switch (function_no)

{

case PROCESS_A:

result = ProcessA(para_in, para_out);

break;

case PROCESS_B:

result = ProcessB(para_in, para_out);

break;

case PROCESS_C:

result = ProcessC(para_in, para_out);

break;

//...

default:

result = UN_DEFINED;

break;

}

return result;

}

int ProcessA(void* para_in, void* para_out){...}

int ProcessB(void* para_in, void* para_out){...}

int ProcessC(void* para_in, void* para_out){...}

//...

上面这种实现方式,分支越多,可读性越差,维护起来也越麻烦。最主要的是,它不够优雅。

//版本2 – 宏定义版

#define DISPATCH_BEGIN(func)switch (func)\

{

#define DISPATCH_FUNCTION(func_c, function)case func_c:\

return = function(para_in, para_out);\

break;

#define DISPATCH_END(code)default:\

result = code;\

}

int ProcessControl(UINT function_no, void* para_in, void* para_out)

{

int result;

DISPATCH_BEGIN(function_no)

DISPATCH_FUNCTION(PROCESS_A, ProcessA)

DISPATCH_FUNCTION(PROCESS_B, ProcessB)

DISPATCH_FUNCTION(PROCESS_C, ProcessC)

//...

DISPATCH_END(UN_DEFINED)

return result;

}

这个版本的代码稍微有了点清爽的感觉。但是用宏是治标不治本的方法。

//版本3 – 表驱动版

typedef struct tagDispatchItem

{

UINT func_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

{

if (function_no == dispatch_table[i].func_no)

return dispatch_table[i].func_ptr(para_in, para_out);

}

return UN_DEFINED;

}

上面采用的是数组形式,还可以换为高级的数据结构,如下所示:

//版本4 – 表驱动版(高级数据结构)

typedef std::hash_map CmdHandlerMap;

CmdHandlerMap HandlerMap;

void InitHandlerMap()

{

HandlerMap[PROCESS_A] = reinterpret_cast(&ProcessA);

HandlerMap[PROCESS_B] = reinterpret_cast(&ProcessB);

HandlerMap[PROCESS_C] = reinterpret_cast(&ProcessC);

//...

}

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;

}

孰优孰劣,一看便知。

点击复制链接 与好友分享!回澳门葡京手机版网址澳门葡京手机版网址
上一篇:git pull失败 error: RPC failed; curl 56 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errfno 10054
下一篇:shell编程之输入输出重定向篇
相关文章
图文推荐
点击排行

关于大家 | 联系大家 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 澳门葡京手机版网址_澳门新莆京娱乐_www.88807.com - 点此进入--致力于做实用的IT技术学习网站

XML 地图 | Sitemap 地图