打造高质量代码之三(表驱动法)

表驱动法是一种编程模式——从表里面查找信息而不是使用逻辑语句(if和case)。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白。但随着逻辑链的越来越复杂,查表法也就愈发显得更具有吸引力。
举例:把字符划分为字母、标点和数字三类。

使用复杂逻辑

if ( (('a' <= inputChar) && (inputChar <= 'z')) || 
   ( ('A' <= inputChar) && (inputChar <= 'Z')) )
{
	charType = letter;
}
else if( (inputChar == ' ') || (inputChar == ',') ||
       (inputChar == '.') || (inputChar == '!') || (inputChar == '(') 
       (inputChar == ')') || (inputChar == ':') || (inputChar == ';')
       (inputChar == '?') || (inputChar == '-') )
{
	charType = punctuation;
}
else if( ('0' <= inputChar) && (inputChar <= '9') )
{
	charType = digit;
}

使用查询表(lookup table)

charType = charTypeTable[ inputChar ];
//这段代码假设charTypeTable数组已经提前创建好了。
//这是你把程序中的信息放在数据里而不是逻辑中——也就是说,放在表中而不是if检测中。

使用表驱动法的两个问题

1、怎样从表中查询条目?
2、在表中存什么样的数据?

(1)直接访问表

示例:一个月中的天数。

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

days = daysPerMonth[ month - 1];

示例:灵活的消息格式。
打印存储在一份文件中的消息,大约有500条消息,每份文件有大约20种不同的消息。这些消息类型通过消息ID区分,每种消息都有自己的格式。
打造高质量代码之三(表驱动法)_第1张图片

基于逻辑的方法
//读消息,检查ID,调用相应ID的子程序来打印。下面是逻辑方法的伪代码:
打造高质量代码之三(表驱动法)_第2张图片
表驱动法
消息阅读子程序由一个循环组成,该循环负责读入每一个消息头,对其ID解码,在Message数组中查询其消息描述,然后每次都调用同一个子程序来解释该消息。用了表驱动法之后,你可以用一张表来描述每种消息的格式,而不用再把它们硬编码进程序逻辑里。这样会降低初期编码的难度,生成更少的代码,并且无须修改代码就可以轻松地进行维护。
打造高质量代码之三(表驱动法)_第3张图片
在这里插入图片描述
打造高质量代码之三(表驱动法)_第4张图片
打造高质量代码之三(表驱动法)_第5张图片
构造查询键值:
有些数据是处于某个范围中的,表的生成会造成空间浪费。比如保险费率问题中,18~30岁是一种费率,这时需要转换这个年龄键值,将年龄区间转换成一个值,18到30岁转换成一个键值,比如说18。
把键值转换提取成独立的子程序,给这个子程序起个好名字,比如说KeyFromAge(), 同样也会明确该数学运算的用意。
如果开发环境中已经提供了现成可用的键值转换功能,那么就用它。例如Java中提供的关联型容器HashMap,可用作根据键值(key)查出实值(value)。

(2)索引访问表
(3)阶梯访问表

总结:本质上,减少重复,充分利用空间的同时利于查找。把知识叠入数据以求逻辑质朴而健壮。

你可能感兴趣的:(优雅代码设计)