备注: 示例中的代码并不是真实代码的完全拷贝
道高一尺,魔高一丈
魔鬼数字在项目中大量出现,是代码可读性维护性变差的重要推手。 为了控制事态恶化,项目中加入findbugs,checkstyle等静态检查工具,试图让人自觉修复魔鬼数字这类头疼的问题。
最近在review N项目的代码时,发现有新童鞋对修复checkstyle的问题热情高涨,有些修改的确是有益的, 但是对魔鬼数字的修改就显得不是正路了。大家先看看:
private static final int INT_2 = 2;
private Static final int INT_80 = 80;
private Static final int INT_1000 = 1000;
private Static final int INT_60000 = 60000;
这种情况以前也出现过,那个时候刚推广checkstyle,结果有人定义了NumberUtil类,里边就有ONE, TWO…等变量, 一直延伸到好几十。这让我非常纠结,劝说了很多次,结果这个类最终还是扎下根来了。我对此深恶痛绝。
今天再次看到这种方式,真是道高一尺魔高一丈呀。我又要发牢骚了。
认清工具的本质
这种做法完全就是为了对付checkstyle,而不是对付那对问题代码。工具本来是想提醒程序员,避免写出难以维护的代码。 结果我们更聪明,把代码藏起来,眼不见为净。这样其实是把数字和变量名直接关联起来了, 你能想象一个叫INT_2的变量值确是1么? 如果在不同含义的逻辑里边使用这样一个魔鬼变量, 一旦值发生变化,就会顺带把不应该修改的地方也改动了。
如果我们真的是为了提高自己的编码水平,提高项目的代码质量,就应该认真的对待这些魔鬼数字。 对于魔鬼数字,应该有一个良好的命名,对于经常出现的,还应该找个合适的地方加以管理。接下来以上面的例子继续分析。
解决魔鬼数字
要解决魔鬼数字,首先是认清魔鬼数字代表的意义,给它起一个合适的名字。
查看源代码,可以发现,做了下面的代码调整:
- 2是某个值在列表中的位置索引,换成XXX_IDX
- 80是http的默认端口,换成DEFAULT_HTTP_PROT
- 1000是用来把秒换成毫秒的,可以用MILLISECONDS_PER_SECOND
- 60000是默认超时时间来的,换成DEFAULT_TIMEOUT
同样,经常会看到魔鬼字符串,”0”,”1”这样的值出现代码里边,也应该 把给他们起一个好的名字,例如作为执行结果,有SUCCESS、FAILED等。
更进一步
需要考虑的还有常量定义的地方,另外考虑使用方法封装来处理魔鬼数字的逻辑。 这样可以隐藏一些细节,把作用域限制在很小的地方。 例如下面经常出现的魔鬼字符串,就可以考虑把整个判断逻辑封装到user类里边去, 而不只是简单的定义出ACTIVE这样一个常量。
// 原有的代码
if("1".equals(user.getStatus())){
// ...
}
// 改造后,"1"作为user的常量使用于isActive方法
if(user.isActive()){
// ...
}
不过话说回来,解决魔鬼数字、字符串之类等’小枝小节’,花费的精力不小。 但不要忽视这些细节,这样可以让自己不断提高对代码的认识,也便于其他人维护你的代码。
对付魔鬼数字,还是不要走捷径的好!
“improve bitter code”系列文章:
- 2012-07-21 improve bitter code
- 2012-07-24 improve bitter code: 迷惑的boolean参数
- 2012-07-24 improve bitter code: 更友好的链式写法
- 2012-07-28 improve bitter code: 看不懂的正则表达式
- 2012-07-29 improve bitter code: ‘不可避免’的重复
- 2012-07-29 improve bitter code: 拘泥于单出口方法
- 2012-07-31 improve bitter code: 对付魔鬼数字
- 2012-08-04 improve bitter code: 多掌握一门语言
- 2012-08-07 improve bitter code: 判空的处理
- 2012-08-15 improve bitter code: 没有行为的封装