我们的项目中是否充斥着类似下面的代码呢?定义一个专门存放常量的java类(接口),很多其他类依赖该常量类。
public interface IConstant
{
int ZERO = 0;
String EMPTY_STRING = "";
}
使用该常量的代码,大致具有如下形式:
List<String> list = new ArrayList<String>(IConstant.ZERO);
if(IConstant.ZERO == list.size())
{
}
int[] array = {1,2,3}
array[IConstant.ZERO];
if(IConstant.EMPTY_STRING.equals(name))
{
}
为什么要把0和""定义成一个常量呢?这是没有正确理解到底什么是魔鬼数字和硬编码。使用常量,出于如下几个原因:
1、为了可读性,一个好的名字显然比一串写死的数字更容易理解。
2、避免冗余,让代码更容易修改,实现一处该,处处该的效果。
3、避免程序员手写常量,不小心写错。比如多写了个0或者是少写了个0等。
4、常量必须是被多个地方使用,而且在不同的地方代表相同的含义。
如果定义的常量没有达到这4个要求中的任意一个,那么可以说这个常量的使用是没有意义的,会导致另一中代码坏味道:没有必要的复杂性。
上面我们举的例子中:0代表的是列表的长度,也代表数组的第一个元素。不满足第1个要求,因为对于程序员来说,这只是最基本的语法,额外定义变量不能提高可读性;不满足第2个要求,因为这些东西是不会变的,不存在修改的可能;不满足第3个要求,有IDE的编译提示,而且常量0并不复杂,不存在写错的可能;不满足第4个要求,因为0一会儿代表长度,一会儿代表数组索引,根本没有办法给0取一个有意义的名称。
第4点需要特别注意:一个常量名称只能代表一个业务含义!让列表长度和数组索引“复用”常量值0,这种做法非常不好。虽然减少了常量的个数,貌似实现了"复用",实际上是增加了代码之间的耦合。举个极端的例子,假如java的语法发生重大改变,数组的第一个元素从1开始而不是0,那我们能将常量ZERO修改成1吗?显然不能,如果修改了,是能够保证数组的正确使用,但是会导致列表长度的判断错误。这种场景下,我们定义的常量ZERO完全没有意义。