//(1-5行)初始化输出值
//(6-102行)超大循环,遍历输入的mnsInfos,对每一项执行以下的操作:
//(8-14行)首先从mnsInfos中取出一组数据并记录其中的所有怪物ID
//(15-21行)如果该组数据为空,则记入输出参数vmnsInfos并跳过
//(22-25行)(如果该组数据不为空)根据这一组怪物ID获取其对应的怪物类型(mnsTypes)及无效怪物的集合
//(26-95行)如果存在部落群和怪物不一致或者怪物类型错误的情况,那么:
// a、(29-42行)若一个有效怪物都没有时,记录无效怪物
// b、(43-94行)否则遍历这一组所有怪物,并分别记录下有效值和无效值,当
//1、数据库中存在怪物信息且类型也有效时,记为有效怪物,并存入输出参数vmnsInfos
//2、怪物ID和对应的怪物类型不一致或怪物不属于部落群,记为无效怪物,并存入输出参数ivmnsInfos
//(96-101行)否则如果部落群和怪物一致,且对应的怪物类型也一致,则将信息都存入vmnsInfos
//(103-105行)循环结束,返回执行成功标识


  从以上的“注释”中,可以看出几点:

  1、虽然该函数有100多行,但是其实逻辑并没有那么复杂。

  2、逻辑并不复杂的代码却写出100多行,其中大量代码都是在做基本的sequence、vector遍历、拷贝的原始动作,这些完全可以剥离出去,使主体逻辑清晰化。

  2、返回值不能指示任何情况,因为只要函数执行完必定返回true;如果中途抛出异常,该函数也没处理,自然也不会有返回值。该设计不是很合理。

  如果有足够的把握,上面的“翻译”过程也可以在脑中进行,无需写出来。

  当代码“翻译”为“注释”后,可将提取出的逻辑与设计和需求进行比对,检查其是否忠实体现了设计,是否完整、准确地实现了需求。

  需求和设计文档这里不给出了,对抽取出的逻辑参考相关文档进行检查不是太困难的事,在此不展开。

  第二步:

  接下来要做的是针对“常规输入”的可能取值进行核查。所谓“常规输入”是指函数的参数,这是函数的显式输入。

  我们知道,任何一段程序都可以用IPO(Input-Process-Output)模型来分析、检查。所以代码检视要做的也是针对所有输入的可能取值,检查代码段是否有正确的处理,能否产生正确的输出。

  函数参数正是显眼明白的输入项,对它的取值采取等价类划分和取边界值,能够检视出代码中是否能够覆盖到各类的输入组合。

  示例代码段一中,函数有两个输入参数hrdId和mnsInfos(余下两个是输出参数),我们一个个地看。

  hrdId在代码中仅有一处使用,即


NPCManagement::MonsterLoader::getMonsterType(hrdId, -1, monsterIds, mnsTypes);


  这是一个外部调用。

  第一条、检视规则:输入参数仅用于外部调用的情况,在代码检视中可不必关注。

  因为通常情况下这样的输入参数不影响被检视函数走向,而是否影响被调用的外部函数、对象,则是应当在其他的检视活动中覆盖的内容。

  该规则,我们在“常规输入”检查阶段跳过这一行。

  第二个参数mnsInfos在整个函数中很多地方都有使用,因此要详细分析。

  第一处用到是在初始化语句中:ivmnsInfos.length(mnsInfos.length());

  我们说过对输入参数仅用于外部调用的情况可以不关注,因此这句略过。

  第二处是作为循环终了判断条件出现: