表驱动取代if和switch结构

背景

在开发过程中,经常遇到需要在不同的场景下调用不同的函数以实现不同的功能(例如消息分发),传统的设计方法中大量的使用 if/else,switch/case结构。如下所示:

假设你需要一个可以返回每个月中天数的函数(为简单起见不考虑闰年),一个比较笨的方法是一个大的if语句:

int iGetMonthDays(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;
}

可以看出本来应该很简单的一件事情,代码却是这么冗余,对于 if/else,switch/case结构的实现方式有两个缺点:

  • 分支越多,可读性越差,维护起来也越麻烦
  • if/else,switch/case结构对于分支的个数也有一定的限制,可扩展性不强。

所以解决这个的办法就可以用表驱动方法表驱动方法是一种使可以在表中查找信息,而不必用很多的逻辑语句(if或Case)来把它们找出来的方法。事实上,任何信息都可以通过表来挑选。在简单的情况下,逻辑语句往往更简单而且更直接。但随着逻辑链的复杂,表就变得越来越富有吸引力了。

基础知识

在使用表驱动方法时需要了解三个核心问题:

  1. 什么是表?
  2. 将在表中存储些什么?
  3. 怎样从表中查询条目?

什么是表

在c/c++中很多都可以作为表,比如数组、哈希表(key-value)等,我们可以选择哈希表,因为在哈希表的查询效率很高。

将在表中存储些什么怎样从表中查询条目

在某些情况下,表查寻的结果是数据,如果是这种情况,你可以把数据存储在表中;在其它情况下,表查寻的结果是动作,在这种情况下,你可以把描述这一动作的代码存储在表中;在某些语言中,也可以把实现这一动作的子程序的调用存储在表中,也就是将函数的指针保存在表中,当查找到这项时,让程序用这个函数指针来调用相应的程序代码,即回调函数,这个就是函数指针在表驱动方法中的应用。

具体使用

// CPacket 为数据包
typedef int(CCommand::*CMDFUNC)(std::list<CPacket>&, CPacket& inPacket); // 回调函数 

std::map<int, CMDFUNC> m_mapFunction; 				// 哈希表:从命令号到功能映射
struct 
{
    int nCmd;
    CMDFUNC func;
}data[] = {
    {1, &CCommand::MakeDirverInfo},
    {2, &CCommand::MakeDirectoryInfor},
    {3, &CCommand::RunFile},
    {4, &CCommand::DownloadFile},
    {5, &CCommand::MouseEvent},
    {6, &CCommand::SendScreen},
    {7, &CCommand::LockMachine},
    {8, &CCommand::UnLockMachine},
    {9, &CCommand::DeleteLocalFile},
    {1981, &CCommand::TestConnect},					
    {-1, NULL},
};

// 添加
for (int i = 0; data[i].nCmd != -1; i++)
{
    m_mapFunction.insert(std::pair<int, CMDFUNC>(data[i].nCmd, data[i].func));
}
// 使用
std::map<int, CMDFUNC>::iterator it = m_mapFunction.find(nCmd);
if (it == m_mapFunction.end())
{
    return -1;
}

总结

扩展个数:switch case最多是256个,而哈希可以无限扩展。

效率比较:switch底层实现大量使用汇编的if else(所以效率比代码if else高),如果case个数非常多,效率会急剧降低;而哈希的效率在选择项少时,效率没有if else、switch case高,但随着个数的增加,优势会越来越明显。

所以如果选择项比较少的时候使用if 和switch效率更高,更合适;但是如果当选择项比较多时使用哈希表查询的效率更高,更合适。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值