以上是题外话, 现在进入正题
今天在面向对象训练营的培训中, 发现了一种新的坏味道. 事情是这样的: 学员在完成按空位绝对数量多少停车的时候, 使用了继承, SmartBoy继承自Boy. 停车是不同的, override; 而取车是一样的, 代码都在基类里. 而在写测试的时候, 我发现他们分成了两派. 一派没有对SmartBoy的取车进行测试, 而另一派做了测试. 组织他们讨论, 两派的理由都有道理: 前者说取车代码只有一份, 前面Boy的测试已经测过了, 因此SmartBoy可以不测; 而后者说从功能上SmartBoy和Boy完全是独立的, 测试用例应该从功能分解下来, 因此应该测. 而你只是内部实现使用了继承, 要是我现在不测, 哪一天你不用继承了, 岂不是有破坏现有功能的风险?
我认为两者都有道理. 且不说可否从单元测试和功能测试的角度来解释(况且前面我们已经说了Unit Level Fucntional Test),单是这种争论的存在我们就可以思考: 是什么让我们陷入了可测可不测, 进退两难的境地?
几秒钟之后我想清楚了, 这是一种坏味道, 原因是这里有重复. 这里虽然没有重复的代码, 但是有重复的概念. SmartBoy根本就不是一个独立的概念. 同样的Boy加不同的选车位的策略才是更基本的概念. 重构到策略模式至少是一种可以消除争论的一种方案, 因为此时取车只有一份了, 无论从代码上还是概念上. 因此前面Boy的测试已经测过了, 我们根本不需要再写一遍
推而广之, 我们可以重新发现一种已知的坏味道: 实现继承. 而可有可无的测试和实现继承在坏味道方面是对偶的.