代码格式化很重要。它太重要了,不能被忽视,同事它也不能过于教条地对待。代码格式化是关于沟通的,而沟通是专业开发人员的首要任务。
垂直格式化
概念间垂直开放性
这个概念包括如何在代码中分隔概念,下面的例子可以说明这一点。
// 良好的垂直开放性
package fitnesse.wikitext.widgets;
import java.util.regex.*;
public class BoldWidget extends ParentWidget {
public static final String REGEXP = "'''.+?'''";
private static final Pattern pattern = Pattern.compile("'''(.+?)'''", Pattern.MULTILINE + Pattern.DOTALL);
public BoldWidget(ParentWidget parent, String text) throws Exception {
super(parent);
Matcher match = pattern.matcher(text);
match.find();
addChildWidgets(match.group(1));
}
public String render() throws Exception {
StringBuffer html = new StringBuffer("<b>");
html.append(childHtml()).append("</b>");
return html.toString();
}
}
// 较差的垂直开放性
package fitnesse.wikitext.widgets;
import java.util.regex.*;
public class BoldWidget extends ParentWidget {
public static final String REGEXP = "'''.+?'''";
private static final Pattern pattern = Pattern.compile("'''(.+?)'''", Pattern.MULTILINE + Pattern.DOTALL);
public BoldWidget(ParentWidget parent, String text) throws Exception {
super(parent);
Matcher match = pattern.matcher(text); match.find(); addChildWidgets(match.group(1));
}
public String render() throws Exception {
StringBuffer html = new StringBuffer("<b>");
html.append(childHtml()).append("</b>");
return html.toString();
}
}
如你所见,第一个示例的可读性优于第二个。
垂直密度
垂直密度意味着紧密关联。因此,紧密相关的代码行应该在垂直方向上显得密集。查看以下示例:
// 较差的垂直密度
public class ReporterConfig {
/**
* The class name of the reporter listener
*/
private String m_className;
/**
* The properties of the reporter listener
*/
private List<Property> m_properties = new ArrayList<Property>();
public void addProperty(Property property) { m_properties.add(property);
}
// 良好的垂直密度
public class ReporterConfig {
private String m_className;
private List<Property> m_properties = new ArrayList<Property>();
public void addProperty(Property property) {
m_properties.add(property);
}
}
第二个代码更容易阅读。它适合一次性浏览。
垂直距离
变量声明。变量应该尽可能靠近其使用位置声明。因为我们的函数非常短,局部变量应该出现在每个函数的顶部。
实例变量,另一方面,应该在类的顶部声明。这不应该增加这些变量的垂直距离,因为在一个设计良好的类中,它们被许多,如果不是所有,类的方法使用。
关于实例变量应该放在哪里,已经有很多争论。在C++中,我们通常采用所谓的剪刀规则,将所有实例变量放在底部。然而,在Java中,常见的惯例是将它们全部放在类的顶部。我看不出有理由遵循任何其他惯例。重要的是在众所周知的地方声明实例变量。每个人都应该知道去哪里查看声明。
依赖函数。如果一个函数调用另一个函数,它们应该在垂直方向上靠近,如果可能的话,调用者应该在被调用者上方。这给程序提供了自然的流程。如果可靠地遵循了这一惯例,读者将能够相信函数定义将紧随其使用之后。
概念亲和性。某些代码片段想要靠近其他代码片段。它们具有某种概念上的亲和性。亲和力越强,它们之间的垂直距离就应该越小。
垂直排序
通常我们希望函数调用依赖指向下方。也就是说,被调用的函数应该在调用函数的下方。这在源代码模块中从高层到低层创造了一个良好的流程。(这与Pascal、C和C++等语言正好相反,这些语言强制在函数使用前定义或至少声明函数)
水平格式化
水平开放性和密度
我们使用水平空白来关联紧密相关的事物,以及将关系较弱的事物分开。示例:
// 良好的水平开放性和密度
private void measureLine(String line) {
lineCount++;
int lineSize = line.length();
totalChars += lineSize;
lineWidthHistogram.addLine(lineSize, lineCount);
recordWidestLine(lineSize);
}
赋值语句有两个明显且主要的元素:左侧和右侧。空格使这种分离变得明显。
水平对齐
// 过时的水平对齐
public class Example implements Base
{
private Socket socket;
private inputStream input;
protected long requestProgress;
public Expediter(Socket s,
inputStream input) {
this.socket = s;
this.input = input;
}
}
在现代语言中,这种类型的对齐是没有用的。对齐似乎强调了错误的事物,引导我的视线远离真正的意图。
// 更好的方法
public class Example implements Base
{
private Socket socket;
private inputStream input;
protected long requestProgress;
public Expediter(Socket s, inputStream input) {
this.socket = s;
this.input = input;
}
}
这是更好的方法。
缩进
缩进很重要,因为它帮助我们拥有可见的层次结构和定义良好的块。
团队规则
每个程序员都有自己喜欢的格式化规则,但如果他在团队中工作,那么团队的规则优先。
开发团队应该就单一的格式化风格达成一致,然后每个团队成员都应该使用那种风格。我们希望软件具有一致的风格。我们不希望它看起来像是一群意见不合的个人编写的。