《代码整洁之道》第 2 章 有意义的命名

第 2 章 有意义的命名

2.2 名副其实

如果名称需要注释来补充,那就不算是名副其实。

public List<int[]> getThem() {
	List<int[]> list1 = new ArrayList<int[]>() ;
	for (int[] x : theList)
		if (x[0] == 4)
			list1.add(x) ;
	return list1;
}

为什么难以说明上列代码要做什么事?里面并没有复杂的表达式。空格和缩进中规中矩。只用到三个变量和两个常量。甚至没有涉及任何其他类或多态方法,只是(或者看起来是) 一个数组的列表而已。问题不在于代码的简洁度,而是在于代码的模糊度:即上下文在代码中未被明确体现的程度。上列代码要求我们了解类似以下问题的答案:
(1) theList 中是什么类型的东西?
(2) theList 零下标条目的意义是什么?
(3) 值 4 的意义是什么?
(4) 我怎么使用返回的列表?
问题的答案没体现在代码段中,可那就是它们该在的地方。

修改方法:

  • 零下标条目是一种状态值,而这种状态值为 4 表示“已标记”。

    if (cell[STATUS_VALUE] == FLAGGED)
      flaggedCells.add(cell);
    
  • 另写一个类,该类包含一个名副其实的函数(isFlagged)从而掩盖住 "4" 这个魔术数。

    if (cell.isFlagged())
      flaggedCells.add(cell)
    

2.3 避免误导

  • 应当避免使用与本意相悖的词。
  • 提防使用不同之处较小的名称。比如用小写字母 l 和大写字母 O 作为变量名。

2.4 做有意义的区分

以数字系列命名(a1、 a2,...N)是依义命名的对立面。这样的名称纯属误导一完全没有提供正确信息;没有提供导向作者意图的线索。

public static void copyChars(char a1[], char a2[]) {
  for (int i = 0; i < a1.length; i++) {
	  a2[i] = a1[i] ;
  }
}

如果参数名改为 sourcedestination,这个函数就会像样许多。

假设你有一个 Product 类。如果还有一个 ProductInfoProductData 类,那它们的名称虽然不同,意思却无区别。Info 和 Data 就像 a、an 和 the 一样,是意义含混的废话。

废话都是冗余。Variable 一词永远不应当出现在变量名中。Table 一词永远不应当出现在表名中。NameString 会比 Name 好吗? 难道 Name 会是-一个浮 点数不成?如果是这样,就触犯了关于误导的规则。设想有个名为 Customer 的类,还有一个名为 CustomerObject 的类。区别何在呢? 哪一个是表示客户历史支付情况的最佳途径?

2.5 使用读得出来的名称

命名时不要使用傻乎乎的自造词,要使用恰当的英语词。

2.6 使用可搜索的名称

单字母名称和数字常量有个问题,就是很难在一大篇文字中找出来。
MAX_CLASSES_PER_STUDENT 很容易,但想找数字 7 就麻烦了,它可能是某些文件名或其他常量定义的一部分,出现在因不同意图而采用的各种表达式中。如果该常量是个长数字,又被人错改过,就会逃过搜索,从而造成错误。

同样,e 也不是个便于搜索的好变量名。它是英文中最常用的字母,在每个程序、每段代码中都有可能出现。由此而见,长名称胜于短名称,搜得到的名称胜于用自造编码代写就的名称。
窃以为单字母名称仅用于短方法中的本地变量。名称长短应与其作用域大小相对应。若变量或常量可能在代码中多处使用,则应赋其以便于搜索的名称。再比较

for (int j=0; j<34; j++) {
	s += (t[j]*4)/5;
}

int realDaysPerIdealDay = 4;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int j=0; j < NUMBER_OF_TASKS; j++) {
  int realTaskDays = taskEstimate[j] * real DaysPerIdealDay;
  int realTaskweeks = (realdays / WORK_DAYS_PER_WEEK) ;
	sum += realTas kWeeks;
}

注意,上面代码中的 sum 并非特别有用的名称,不过它至少搜得到。采用能表达意图的名称,貌似拉长了函数代码,但要想想看,WORK_DAYS_PER_WEEK 要比数字 5 好找得多,而列表中也只剩下了体现作者意图的名称。

2.7 避免使用编码

匈牙利语标记法(Hungarian Notation,HN)和成员前缀已经过时,是旧代码的标志物。

2.9 类名

类名和对象名应该是名词或名词短语,如 CustomerWikiPageAccountAddressParser。避免使用 ManagerProcessorDataInfo 这样的类名。类名不应当是动词。

2.10 方法名

方法名应当是动词或动词短语,如 postPaymentdeletePagesave。属性访问器、修改器和断言应该根据其值命名,并依 Javabean 标准加上 getsetis 前缀。

string name = employee.getName();
customer.setName("mike") ;
if (paycheck.isPosted())...

重载构造器时,使用描述了参数的静态工厂方法名。例如,
Complex fulcrumPoint = Complex.FromRealNumber (23.0);
通常好于
Complex fulcrumPoint = new Complex (23.0);
可以考虑将相应的构造器设置为 private,强制使用这种命名手段。

2.16 添加有意义的语境

设想你有名为 firstNamelastNamestreethouseNumbercitystatezipcode 的变量。当它们搁一块儿的时候, 很明确是构成了一个地址。不过,假使只是在某个方法中看见孤零零一个 state 变量呢?你会理所当然推断那是某个地址的一部分吗?

可以添加前缀 addrFirstNameaddrLastNameaddrState等,以此提供语境。至少,读者会明白这些变量是某个更大结构的一部分。当然,更好的方案是创建名为 Address 的类。这样,即便是编译器也会知道这些变量隶属某个更大的概念了。

posted @ 2023-07-20 09:16  CoolGin  阅读(18)  评论(0编辑  收藏  举报