1.对局部变量(local variables),字段(fields),参数(method arguments)这三种变量的命名没有区分,造成了代码的阅读困难,增加了代码的维护成本。
作者举了个例子:
- public boolean equals (Object arg) {
- if (! (arg instanceof Range)) return false;
- Range other = (Range) arg;
- return start.equals(other.start) && end.equals(other.end);
- }
在这个方法中,arg直接用argument的缩写,虽然大家一看就知道这是参数了,但这种命名方式却丢失了参数代表的对象本身的含义。大家知道这是参数,却不知道这是什么参数。如果方法的参数多一点,都按照arg1,arg2这样的方式命名,阅读代码的时候很头疼。另外两个字段变量,start和end,突然凭空而出,想一下才知道这应该是字段。当然,这个方法很短,造成的困难还不大,如果这个方法比较长的话,突然看到start和end两个变量,一般会先在前面找一下是不是局部变量,然后才能确定是类的字段变量。
这个问题貌似微不足道,但为什么要让代码阅读者花费额外时间在这些琐碎的问题上呢?如果有个方案能让代码阅读者一目了然的明白变量是那种变量,为什么不采用呢?就如同Steve McConnell在 《代码大全》中说的:"让人费神去琢磨神秘杀人凶手这没有问题,但你不需要琢磨程序代码,代码是用来阅读的。"
作者提出了解决方案:
- 方法参数用前缀a开始
- 类字段变量用前缀f开始
- 局部变量不用前缀
修正后的代码样式应该是:
- public boolean equals (Object aOther) {
- if (! (aOther instanceof Range)) return false;
- Range other = (Range) aOther;
- return fStart.equals(other.fStart) && fEnd.equals(other.fEnd);
- }
这样的代码看起来一目了然,如果你没有一目了然,说明还是习惯问题,习惯养成了就好了。
不过作者的方案里,给类字段变量前面加 f 前缀,如果用代码生成工具生成get,set方法是会比较麻烦。get,set方法中我们不希望出现个f。不过这个问题可以用修改代码生成工具的方式解决。如果这个习惯普遍被java界接受,这些应该都不成问题了。
2.类成员的排序没有按照成员的作用域(scope) 的大小从大到小排列,而是喜欢把private放在前面。
作者举了一个常见的类样式:
- public class OilWell implements EnergySource {
- private Long id;
- private String name;
- private String location;
- private Date discoveryDate;
- private Long totalReserves;
- private Long productionToDate;
- public Long getId() {
- return id;
- }
- public void setId(Long id) {
- this.id = id;
- }
- //..elided
- }
这种方式将private变量放在最前面。作者认为应该倒过来,把private变量的申明放在最后面。
因为人们认识一个事物的通常过程都是从一般到特殊,从抽象层次来说,是从高到底的认识过程。如果你倒过来的话,就不能从整体上把握事物,也不能抓住事物的本质,只能在一堆具体的片段事实中迷失。
整体的抽象允许你忽略细节。抽象的层次越高,你可以忽略越多的细节。读者阅读一个类时可以忽略的细节越多他会越高兴。脑袋里填充太多的细节是痛苦的,所以细节越少越好。因此,将private成员方在最后会显得更富有同情心,因为这样阻止了不必要的细节显露给读者。
原来C++程序的习惯也是把private成员放在最开始。然而,C++社区迅速的认识到这是一个有害的规范,这个规范现在已经被修正。(参看 a typical C++ style guide )
注意:public 接口应该放在class的最开始,其次是protected成员,最后是private成员。原因是:
- 程序员应该更关心接口而不是具体实现。
- 当程序员需要用一个类的时候,他们需要的是接口而不是实现。
把接口放在开始是非常有意义的。把实现部分,private 片段,放在开始是一个历史遗留问题。最后还是要反复强调一下,一个类的接口的重要性超过实现细节。
将私有成员放在类的开始是一个等待打破的怀习惯,它似乎是sun早期的编码规范造成的。
将代码按照javadoc的顺序编排是非常好的:首先是构造方法,然后是非私有方法,最后是私有字段和方法。这样读者阅读的时候很自然的从抽象层次的高向低运动。