14.3 名称应当准确
好的名字有两个属性:精确性和一致性。让我们从精确性开始。名称最常见的问题是它们过于笼统或模糊;因此,读者很难分辨出这个名称指的是什么;读者可能会认为这个名称指的是某个与实际情况不同的东西,就像前面block
的bug一样。考虑一下下面的方法声明:
术语“计数”太笼统了:什么的计数?如果有人看到这个方法的调用,他们不太可能知道它是做什么的,除非他们阅读它的文档。像getActiveIndexlets
或numIndexlets
这样更精确的名称会更好:有了这些名称,读者可能就能猜到这个方法的返回值,而不必看它的文档。
下面是一些其他的名称不够精确的例子,来自不同的学生项目:
一个建立GUI文本编辑器的项目使用名称
x
和y
来指向文件中的一个字符的位置。这些名称太通用了。它们可以代表很多东西;例如,它们也可能代表一个字符在屏幕上的坐标(像素)。孤立地看到x
这个名称的人不太可能认为它指的是文本行中的一个字符的位置。如果使用charIndex
和lineIndex
这样的名字,代码会更加清晰,它们反映了代码所实现的特定抽象。另一个编辑器项目包含以下代码:
// Blink state: true when cursor visible.
private boolean blinkStatus = true;
blinkStatus
这个名字并没有传达足够的信息。“status”这个词对于一个布尔值来说太模糊了:它没有提供关于true和false意味着什么的线索。“blink”这个词也很含糊,因为它没有指出什么在闪烁。下面的替代方案更好:// Controls cursor blinking: true means the cursor is visible, // false means the cursor is not displayed.
private boolean cursorVisible = true;
cursorVisible
这个名字传达了更多的信息;例如,它允许读者猜测一个真值的含义(作为一般规则,布尔变量的名称应当总是谓语)。名字中不再有“blink”这个词,所以如果读者想知道为什么光标不总是可见的,就必须查阅文档;这种信息不太重要。一个实施共识协议的项目包含以下代码:
// Value representing that the server has not voted (yet) for // anyone for the current election term.
private static final String VOTED_FOR_SENTINEL_VALUE = "null";
这个值的名称表明它是特殊的,但它没有说特殊的含义是什么。一个更具体的名字,如NOT_YET_VOTED
会更好。一个名称为
result
的变量被用在一个没有返回值的方法中。这个名字有多个问题。首先,它造成了一种误导性的印象,即它将是该方法的返回值。其次,它基本上没有提供关于它实际持有什么的信息,只是说它是某个计算值。该名称应提供有关结果实际是什么的信息,例如mergedLine
或totalChars
。在那些确实有返回值的方法中,使用result
这个名称是合理的。这个名称还是有点笼统,但是读者可以通过查看方法的文档来了解它的含义,而且知道这个值最终会成为返回值也很有帮助。
像所有的规则一样,关于选择精确名称的规则也有一些例外。例如,使用i
和j
这样的通用名称作为循环迭代变量是可以的,只要循环只跨越几行代码。如果你能看到一个变量的整个使用范围,那么这个变量的含义很可能从代码中就能看出来,所以你不需要一个很长的名字。例如,考虑下面的代码:
从这段代码可以看出,i
被用来在某个实体中迭代每一行。如果循环变得很长,以至于你无法一下子看到它,或者如果迭代变量的含义更难从代码中弄清楚,那么就需要一个更具描述性的名字。
名称也有可能过于具体,比如在下面对一个删除某范围内文本的方法的声明中:
参数名称selection
过于具体,因为它表明被删除的文本在用户界面上总是被选中的。然而,这个方法可以在任何范围的文本上调用,无论是否选中。因此,参数名应该更通用,比如说range
。
如果你发现很难为一个特定的变量想出一个准确、直观而又不会太长的名称,这就是一个危险信号。这表明该变量可能没有一个明确的定义或目的。当这种情况发生时,请考虑其他因素。例如,也许你正试图用一个变量来代表几件事情;如果是这样,把表示的内容分成多个变量可能会使每个变量的定义更简单。选择好名称的过程可以通过发现不足来改进你的设计。
Last updated