表驱动法最常用的一种场景是用其替代if和case语句,使用查表的方式实现代码逻辑,其可以以使代码更为简单明了,同时可以获得更优的执行效率。但其还有一种运用场景:可以消除冗余代码,使得代码更灵活,方便应对将来需求的变化。
假设下面一段代码需要初始化一些ICON图标:
m_ImageList.Add(LoadIcon(hResource, MAKEINTRESOURCE(ICON1)));
m_ImageList.Add(LoadIcon(hResource, MAKEINTRESOURCE(ICON2)));
m_ImageList.Add(LoadIcon(hResource, MAKEINTRESOURCE(ICON3)));
我们可以忽略这些代码的实际含义,而仅仅只关注代码的逻辑结构。可以发现,每一行代码中大部分内容都是相同的,即ICON1前面的部分:
m_ImageList.Add(LoadIcon(hResource, MAKEINTRESOURCE(
其实这也是冗余代码的一种。如果还需要再初始化第4个ICON时,你可能会采用复制粘贴的方法:把第3行代码复制一份,然后把ICON3改为ICON4:
m_ImageList.Add(LoadIcon(hResource, MAKEINTRESOURCE(ICON1)));
m_ImageList.Add(LoadIcon(hResource, MAKEINTRESOURCE(ICON2)));
m_ImageList.Add(LoadIcon(hResource, MAKEINTRESOURCE(ICON3)));
m_ImageList.Add(LoadIcon(hResource, MAKEINTRESOURCE(ICON4)));
然而,如果ICON的个数越来越多,冗余代码的问题就会越来越明显。可以想象如果有10个ICON时,这段代码会变得更加的臃肿。
在写代码时有一个信号需要注意!如果你经常用到复制粘贴,此时你需要停下来好好思考。一方面这会导致冗余代码;另一方面肯定有更为灵活的方法避免冗余代码。针对上面的这种情况,使用表驱动法就是一个很好的解决方案。
这类冗余代码通常都可以分为两部分,一部分是固定的,一部分是变化。我们可以把变化的部分提取出来,放到数组当中,然后将固定的部分放入循环体内。下面就是采用表驱动法优化后的代码:
int iconIds[] = {ICON1, ICON2, ICON3, ICON4};
for(int i = 0; i < sizeof(iconIds)/sizeof(iconIds[0]); i++){
m_ImageList.Add(LoadIcon(hResource, MAKEINTRESOURCE(iconIds[i])));
}
第1行是变化的部分,用一个数组iconIds对不同的ICON ID进行保存。后面的for循环是固定的部分,对每一个iconIds[i]进行相同的操作。
当需要初始化的ICON个数增加到10个时,仅需要修改数组的初始化部分即可,代码并不会显得臃肿:
int iconIds[] = {ICON1, ICON2, ICON3, ICON4, ICON5,
ICON6, ICON7, ICON8, ICON9, ICON10};
for(int i = 0; i < sizeof(iconIds)/sizeof(iconIds[0]); i++){
m_ImageList.Add(LoadIcon(hResource, MAKEINTRESOURCE(iconIds[i])));
}
运用表驱动法的核心思路就是:将代码中容易变化的部分抽取出来,这样当需求变化时所需修改的地方就会相对集中。这样可以提高效率,避免犯错。
另外在使用这个方法时,有几个细节需要注意。
第一、不要直接指定数组中元素的个数。比如这样:
int iconIds[3] = {ICON1, ICON2, ICON3};
上面数组中有3个元素,在数组iconIds定义是在中括号[ ]里填入了3。而当元素个数需要扩大到4个时,就需要改两个地方。第一个地方是将中括号[ ]里的3改成4,第二个地方是在数组初始化列表中添加ICON4 :
int iconIds[4] = {ICON1, ICON2, ICON3, ICON4};
第二、不要直接指定for循环中的循环次数。如果写成这样:
for(int i = 0; i < 3; i++){
当数组元素个数变化时,仍然需要修改两个地方。因此这里使用了C/C++的语法特性,用sizeof(iconIds)/sizeof(iconIds[0])直接计算出了数组元素的个数,而且数组内容变化时这里不需要修改。当然如果是JAVA代码,可以使用iconIds.length来代替。
总之将变化的地方集中在一处,一次需求变更只集中改一个地方。