注:本文所有代码来自 http://www.codeproject.com/Articles/42732/Table-driven-Approach
在许多程序中,经常需要处理那些拥有种种色色不同特性的实体,最直接的思路是用case语句或者if-else语句处理这些不同的实体。然而,如果这类实体的数量若足够庞大,将会产生大量代码,臃肿并难以整理和维护。
先通过一对实例感受一下:
// A text adventure game if(strcmpi(command, "north") == 0) { if(cur_location->north) GoToLocation(cur_location->north); else Print("Cannot go there"); } else if(strcmpi(command, "east") == 0) { if(cur_location->east) GoToLocation(cur_location->east); else Print("Cannot go there"); } else if(strcmpi(command, "south") == 0) { if(cur_location->south) GoToLocation(cur_location->south); else Print("Cannot go there"); } else if(strcmpi(command, "west") == 0) { if(cur_location->west) GoToLocation(cur_location->west); else Print("Cannot go there"); }
相同功能的其他代码:
enum SIDE {SIDE_NORTH = 0, SIDE_EAST, SIDE_SOUTH, SIDE_WEST}; struct COMMAND { const char * name; SIDE side; }; static const COMMAND commands[] = { {"north", SIDE_NORTH}, {"east", SIDE_EAST}, {"south", SIDE_SOUTH}, {"west", SIDE_WEST}, }; for(int i = 0; i < NUM_OF(commands); i++) if(strcmpi(commands[i].name, command) == 0) { SIDE d = commands[i].side; if(cur_location->sides[d]) GoToLocation(cur_location->sides[d]); else Print("Cannot go there"); }
从上面两段代码我们可以看出,第二段将实体从条件语句中分离出来,使得程序框架更加清晰;为了增加command names,现在只需要在一处修改代码。当数据量足够大时,可以分很方便地增添、删减或者替换,非常有利于维护。
正式定义前,再用一对代码来加强理解。(举例来自书籍《Refactoring》,Martin Fowler)
// calculating the price for renting a movie double result = 0; switch(movieType) { case Movie.REGULAR: result += 2; if(daysRented > 2) result += (daysRented - 2) * 1.5; break; case Movie.NEW_RELEASE: result += daysRented * 3; break; case Movie.CHILDRENS: result += 1.5; if(daysRented > 3) result += (daysRented - 3) * 1.5; break; }
使用数组后的优化解决方案:
enum MovieType {Regular = 0, NewRelease = 1, Childrens = 2}; // Regular NewRelease Childrens const double initialCharge[] = {2, 0, 1.5}; const double initialDays[] = {2, 0, 3}; const double multiplier[] = {1.5, 3, 1.5}; double price = initialCharge[movie_type]; if(daysRented > initialDays[movie_type]) price += (daysRented - initialDays[movie_type]) * multiplier[movie_type];
以上举例能非常明显的展现出表驱动设计的优点:Table-Driven代码更快、更短、更容易维护!
如果使用表驱动来整理在之前博客中写到的迷宫问题,代码最少可以简短200行!学到的太晚了!
在此给出Table-Driven Design定义:
表驱动设计是软件开发工程中的一种方法,通过从程序代码中分离的控制变量以及参数并将其存储在外部表格中的处理来简化、概括程序。主要目的在于将控制变量从程序逻辑中脱离以及着重于构建程序的模块化框架,来减轻因变更数据产生的管理工作量。
人类是智慧的,代码是伟大的!如同现实世界一样,计算机世界也有着太多东西值得我们去探索和发现!
加油吧!少年们!
大三上
2016/11/15 上午