《Clean Code - 代码整洁之道》 - 有意义的名称

737 阅读6分钟

本文是对鲍勃大叔(Robert C. Martin)(韩磊 译)一书《Clean Code - 代码整洁之道》读后摘录总结。如有侵权请联系删除。

有意义的名称

1、名副其实

变量、函数或类的名称应该已经答复了所有的大问题。它应该告诉你,它为什么存在,它做什么事,应该怎么用。如果名称需要注释来补充,那就不算事名副其

2、避免误导

程序员必须避免留下掩藏代码本意的错误线索。应当避免使用与本意相悖的词,例如某些平台的专有名词用作变量名。

提防使用外形相似度较高的名称。例如,XYZControllerForEfficientHandlingOfStrings 和 XYZControllerForEfficientStorageOfStrings

误导性名称真正可怕的例子:小写字母 l 和大写字母 O,尤其是在组合使用的时候,他们看起来完全像是“一”和“零”。

3、做有意义的区分

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

如果缺少明确约定,那么变量 moneyAmount 与 money 就没区别,customerInfo 与 customer 没区别,accountData 与 account 没区别,theMessage 也与 message 没区别。要区分名称,就要以读者能鉴别不同之处的方式来区分。

4、使用读得出来的名称

应该使用恰当的英语词,而非自造词

例如:

class DtaRcre102{
	private Date genymdhms;
	private Date modymdhms;
	private final String pszqint = "102";
}

修改以后:

class Customer{
	private Date generationTimestamp;
	private Date modificationTimestamp;
	private final String recordId = "102";
}

5、使用可搜索的名称

长名称胜于短名称,搜得到的名称胜于用自造编码代写的名称。名称长短应该与其作用域大小相对应。

例如:

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<34; j++){
	int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
	int realTaskWeeks = (realTaskDays / WORK_DAYS_PER_WEEK);
	sum += realTaskWeeks;
}

6、避免使用编码

6.1、匈牙利语标记法

例如:bBusy 代表一个类型为 boolean、名称为 Busy 的变量。

6.2、成员前缀

不必用 m_  前缀来表示成员变量。应当把类和函数做的足够小,以消除对成员前缀的需要。

6.3、接口和实现

有时也会出现采用编码的特殊情形。比如,你在做一个创建形状用的抽象工厂,该工厂是一个接口,要用具体类来实现。你怎么来命名工厂和具体类呢?IShapeFactory 和 ShapeFactory 吗?我喜欢不加修饰的接口。前导字母 I 被滥用到了说好听点是干扰,说难听点根本就是废话的程度。我不想让用户知道我给他们的是接口,而就想让他们知道那是一个 ShapeFactory。如果在接口和实现中必须选择其一来编码的话,我宁肯选择实现。 ShapeFactoryImp,甚至是丑陋的 CShapeFractory,都比接口名称编码好。

7、避免思维映射

不应当让读者在脑海中把你的名称翻译为他们熟知的名称,这种问题经常出现在选择是使用问题领域术语还是解决方案领域术语时。

8、类名

类名和对象名应该是名词或名词短语,例如 CustomerWikiPageAccount 或 AddressParser。应该避免使用 ManagerProcessorData 或 Info 这样的类名。类型不应当是动词。

9、方法名

方法名应当是动词或动词短语,如 postPaymentdeletePage 或 save。属性访问器(accessor)、修改器(mutator)和断言(predicate)应该根据其值命名,并依 JavaBean 标准加上 getset 和 is

10、别抖机灵

如果名称太耍宝,那就只有同作者一般有幽默感的人才能记住,而且还是在他们记得那个笑话的时候才行。

宁可明确,毋为好玩。

抖机灵在代码中经常体现为使用俗语或俚语。

11、每个概念对应一个词

给每个抽象概念选一个词,并且一以贯之。例如,使用 fetchretrive 和 get 来给多个类中的同种方法命名。你怎么记得住是哪个类中的哪个方法呢?

函数名称应当独一无二,而且要保持一致,这样你才能不借助多余的浏览就找到正确的方法。

同样,如果在一堆代码中有 controller,有 manager,还有 driver,就会令人困惑。DeviceManager 和 Protocol Controller 之间有何根本区别?为什么不全用 controller 或 manager 呢?他们都是 Drivers 吗?这种名称,让人觉得这两个对象是不同类型的,也分属不同的类。

12、别用双关语

避免将统一单词用于不同目的。同一术语用于不同概念,基本上就是双关语了。

比如,在多个类中都有 add 方法,该方法通过增加或连接两个现存值来获得新值。假设要写一个新类,该类中又一个方法,把单个参数放到群集(collection)中。该把这个方法叫做 add 吗?这样做貌似和其他 add 方法保持了一致,但实际上语义却不同,应该用 insert 或 append 之类的词来命名才对。把该方法命名为 add,就是双关语了。

13、使用解决方案领域名称

记住,只有程序员才会读你的代码。所以,尽管用那些计算机科学 ( Computer Science,CS)术语、算法名、模式名、数学术语吧。依据问题所涉领域来命名可不算是聪明的做法,因为不该让协作者老是跑去问客户每个名称的含义,其实他们早该通过另一名称了解这个概念了。

对于熟悉访问者(VISITOR)模式的程序员来说,名称 AccountVisitor 富有意义。哪个程序员会不知道 JobQueue 的意思呢?程序员要做太多技术性工作,给这些事起个技术性的名称,通常是最靠谱的做法。

14、使用源自所涉问题领域的名称

如果不能用程序员熟悉的术语来给手头的工作命名,就采用从所涉问题领域得来的名称吧。至少,负责维护代码的程序员就能去请教领域专家了。 优秀的程序员和设计师,其工作之一就是分离解決方案领域和问题领域的概念。与所涉问题领城更为贴近的代码,应当采用源自问题领域的名称。

15、添加有意义的语境

设想你有名为 firstNamelastNamestreethouseNumbercitystate 的变量。把它们放一块儿的时候,很明显构成了一个地址。但是,假使只是在某个方法中看见孤零零的一个 state 变量呢?你会理所当然地推断那是某个地址的一部分吗? 可以添加前级 addrFirstNameaddrLastNameaddrState 等,以此提供语境。至少,读者会明白这些变量是某个更大结构的一部分。当然,更好的方案是创建名为 Address 的类。这样,即便是编译器也会知道这些变量隶属某个更大的概念了。

16、不要添加没用的语境

假若有一个名为“加油站豪华版”(Gas Station Deluxe)的应用,在其中给每个类添加 GSD 前缀就不是什么好点子。

只要短名称足够清楚,就比长名称好。别给名称添加不必要的语境。