在编写代码中,有时候会需要if-else分支。
当需要多重筛选时,就会用到多分支结构:
if(条件1)
{
分支流程1
}
else if(条件2)
{
分支流程2
}
……
else
{
分支流程n
}
过长的多分支结构常被视为软件中的不良结构,因为它违背了OCP原则(开放、封闭原则),每当需要新增一种条件判断处理时,就要新增一个if-else分支。
在很多情况下,使用函数表结构是避免过长的分支结构的有效方法,下面以「狼、羊和菜过河」问题的求解算法中用到函数表结构代替过长的多分支结构的例子。农夫一共可以采取8种动作,每种动作都对应一个状态转变处理流程。如果采用if-else多分支结构,处理状态转换的代码将会非常长,为了避免过长的分支跳转代码,算法采用了函数表结构。首先声明函数表项的定义:
typedef bool (*ProcessFuncPtr)(const ItemState& current, ItemState& next);
struct ActionProcess{
Action act;
ProcessNextFuncPtr processFunc;
}
然后分别为农夫的8个动作指定处理函数,得到函数的定义:
ActionProcess actMap[]=
{
{FARMER_GO, ProcessFarmerGo},
{FARMER_GO_TAKE_WOLF, ProcessFarmerGoTakeWolf},
{FARMER_GO_TAKE_SHEEP, ProcessFarmerGoTakeSheep},
{FARMER_GO_VEGETABLE, ProcessFarmerGoVegetable},
{FARMER_BACK, ProcessFarmerBack},
{FARMER_BACK_TAKE_WOLF, ProcessFarmerBackTakeWolf},
{FARMER_BACK_TAKE_SHEEP, ProcessFarmerBackTakeSheep},
{FARMER_BACK_TAKE_VEGETABLE, ProcessFarmerBackVegetable},
};
如果用if-else结构,处理状态转换可能需要30多行代码,而利用这个函数表,处理状态转换的代码只有几行:
ItemState next;
for(int i=0;i<sizeof(actMap)/sizeof(actMap[0]);i++)
{
if(actMap[i].act == action)
{
actMap[i].processFunc(current, next);
break;
}
}
如果将这个函数表存入一个关联容器(比如std:map)中,则循环体的代码都可以省去。如果随着算法演化,有新的动作需要处理,则只需要在函数表中添加新的条目即可,状态转换的代码不需要做任何改动。
——摘自王晓华的《算法的乐趣》2.1.3章节