代码改变世界

也说魔数与魔字符串

2005-07-06 23:22  FantasySoft  阅读(2574)  评论(9编辑  收藏  举报

         看了叙远兄写的.net中的魔字符串,还有birdsome的评论,颇有启发。
         所谓魔数和魔字符串就是在代码中直接使用某一个数字或者字符串,而不是常量。譬如一个很简单的根
据职位计算薪水的方法:

public int getSalary(String title, int grade) {
    
if ("Programmer"
.equals(title)) 
        
return grade * 500 + 700
;
    
else if ("Tester"
.equals(title))
        
return grade * 500 + 800
;
    
else if ("Analyst"
.equals(title))
        
return grade * 800 + 1000
;
}

        在这个方法里面,"Programmer","Tester"和"Analyst"是所谓的魔字符串(Magic String),而500, 700,800和1000就是所谓的魔数(Magic Number)了。 咋一看,代码这样写也没有什么问题,但是,仔细思考一下就会发现,如果这种随手捻来的字符串和数字散布于程序当中,随处可见的话,是会有很多弊病的。我们先来分析三个魔字符串。虽然三个Magic String的意义很明显,并不影响到代码的可读性,但是这样却增加了出错的概率,并且忽略了具体的语义环境。我们很容易就会想到,像"Programmer"这个单词散布在多个方法中,一个大小写的笔误就会产生bug。同时,"Programmer"在计算薪水的方法中代表着职位,但是在统计公司订阅的杂志的方法中,也许就要代表一本杂志的名称了。然而这种语义环境是无法通过一个单纯的"Programmer"就能体现出来的。
        而Magic Number的问题就更大了,首先是影响了代码的可读性,谁会知道500和800是薪水基数,700是补
贴呢?而且更糟糕的是,如果薪水基数发生改变的时候,那么就得找人把这些500,700,800的数字找出来一个一个地update,那可是一件够郁闷的事情了。
        如果我们拥有一个常量定义的interface,代码就会变漂亮起来了:

public int getSalary(String title, int grade) {
    
if
 (Constants.TITLE_PROGRAMMER.equals(title)) 
        
return grade * Constants.BASE_SALARY_LOW +
 Constants.ALLOWANCE_LOW;
    
else if (Constants.TITLE_TESTER
.equals(title))
        
return grade * Constants.BASE_SALARY_LOW +
 Constants.ALLOWANCE_MEDIUM;
    
else if (Constants.TITLE_ANALYST
.equals(title))
        
return grade * Constants.BASE_SALARY_HIGH +
 Constants.ALLOWANCE_HIGH;
}

        从以上的分析,在一个Project里面,避免使用魔数(Magic Number)和魔字符串(Magic String)是相当必要的。通过定义的常量去access特定的字符串和数字也已经是软件开发的standard。那么是不是所有的数字和字符串都应该定义成常量呢?或许有朋友会认为所有的数字和字符串都应该定义成常量,但是我觉得,每个字符串确实是应该定义成常量的,但是对于数字而言,如果数字本身的语义没有得到延伸,那么就不应该定义成常量。譬如数组的index就不应该定义成变量。 像这样的代码:

String building = address[Constants.ONE]; 
            //
 在Constants这个interface中,ONE的定义为 final int ONE = 1;

        你一定会觉得这样的代码就是画蛇添足, 因为ONE就是1,它没有其他特别的含义,不像上面代码中的500和700。而且如果真的要这样定义的话,出现了有上百个元素的数组的时候,那么你就得定义上百个没有任何意义的常量了。是不是很FT呢?
        总之,任何策略的使用,还是一个度最重要。