前言
Phil Karlton有句名言:“计算机科学中只有两个难题:缓存失效和命名”。
平常我们在命名函数的时候,难免会有这样的疑问:我到底要给它命一个什么样的名字呢?既要达到方便写代码的人的后续操作,又要使后来读代码的人清晰易懂。这看似简单的代码命名,实际上背后藏着很深的学问。
我们知道,命名的目的是为了方便人和计算机的理解,所以我们可以说命名实际上也是注释的一种,它和代码中**//**后的注释同样重要。一个好的命名可以让人知道你的代码所要表达的意思。
以下是一个例子:
假设当前有个有关链表的函数需要完成删除操作,请你对这个函数进行命名:
A.DelLT
B.DeleteLinkLIst
C.DelLinkList
请问你会选择以上哪个选项呢?
让我们分析:首先,我们需要完成删除操作,删除作为一个动词,在英文中翻译为Delete,那么在函数的命名中,我们需要让读者明白这个操作是干什么的,也就需要用到Delete这个单词;其次,这个操作是针对链表的,那么在命名中也要包括可以代表链表的名词。可见我们对于函数的命名需要包含以上两个基本的含义,那么怎样做才能让命名看起来既整洁又明了呢?接下来我会介绍几种常见的命名方法。
常见命名方法
匈牙利命名
匈牙利命名法是一种最初由微软公司的程序员Charles Simonyi提出,并在Windows编程中得到广泛应用的命名规范。它**以变量的数据类型作为前缀,然后跟上变量的描述性名称。**基本原则:变量名=属性+类型+对象描述
以我们举例中的链表来说,假设我们有一个单向链表,其中每个节点包含一个整数值和一个指向下一个节点的指针。我们可以按照以下方式命名:
- 链表节点的命名:我们可以将节点的数据类型作为前缀,然后跟上节点的描述性名称。例如,对于存储整数值的链表节点,我们可以将其命名为IntNode/iNode。
- 链表的命名:对于整数值的单向链表,我们可以将链表的数据类型作为前缀,然后跟上链表的描述性名称。例如,我们可以将整数值的单向链表命名为IntLinkedList/iLinkedList。
int iNode int iLinkedList//前缀都是类型,至于属性根据实际情况来判定
以下是属性的具体缩写:
g_ 全局变量 c_ 常量 m_ c++类成员变量 s_ 静态变量
以下是前缀类型的具体缩写:
a 数组(Array) b 布尔值(Boolean) by 字节(Byte) c 有符号字符(Char) cb 无符号字符(Char Byte,并没有神马人用的) cr 颜色参考值(Color Ref) cx,cy 坐标差(长度 Short Int) dw 双字(Double Word) fn 函数(Function) h Handle(句柄) i 整形(Int) l 长整型(Long Int) lp 长指针(Long Pointer) m_ 类成员(Class Member) n 短整型(Short Int) np 近程指针(Near Pointer) p 指针(Pointer) s 字符串(String) sz 以 Null 做结尾的字符串型(String with Zero End) w 字(Word)
这种命名法已经是创造较为古早的命名办法。在那个IDE还不成熟的年代,它是不会给你提示的,所以这种规范在当时可以较好的规避这个问题。当然现在匈牙利命名实际上也在某些时候起着较为高效的命名作用。
驼峰命名法
驼峰命名法又分为小驼峰式命名法和大驼峰式命名法。
我们依照驼峰来思考这类命名法的特点:驼峰可以看作是两边低中间高的一个峰的结构,多个驼峰排列在一起时,就会呈现高-低-高-低-高这样的排列形式;在命名中我们把大写字母看成是峰顶,小写字母就是相对的峰谷,所以不难看出这种命名法的特点是:将单词的首字母大写,其他小写,组合在一起形成驼峰结构。
大驼峰式命名法
它的特点是每个单词的首字母都大写,单词之间没有下划线或其他分隔符,形式上类似于驼峰的背部。例如:
DataBaseUser StudentInfomation
大驼峰命名法通常用于表示类名或接口名,因为类名通常是一种抽象概念,而大驼峰命名法的格式能够清晰地表示类名的含义。例如,Person、Car、UserInfo等都是使用大驼峰命名法命名的类名。
小驼峰式命名法
它的特点是除了第一个单词外其他单词首字母都大写,单词之间没有下划线或其他分隔符,形式上类似于驼峰的背部。例如:
myVariable getUserInfo calculateTota
小驼峰命名法通常用于表示变量名、函数名等具体实体的命名,因为这些命名通常是与具体操作或属性相关联的。小驼峰命名法的格式能够清晰地表示变量或函数的含义,使代码易于理解和维护。
蛇形命名法/下划线命名法
这种命名方式多用于单词较多的时候,它的特点是各个单词之间使用下划线“_”连接,并且通常所有字母都使用小写。例如:
my_variable get_user_info calculate_total
当我们命名所需单词较多时,往往蛇形命名法更占优。
void should_get_200_status_code_when_request_is_valid()//蛇形 void shouldGet200StatusCodoWhenRequestIsValid()//驼峰
很明显蛇形命名法的可读性更高。
串式命名法
这种命名方式和蛇形命名法很像,它的特点是各个单词之间使用连字符“-”连接,并且通常所有字母都使用小写。例如:
my-variable get-user-info calculate-total
结合使用
实际上,没有绝对的需要使用指定的哪种方法来命名,你完全可以创造你自己的命名方式,只要它足够方便足够可读,你也完全可以将以上的命名方式结合起来使用,来形成最适合自己的那种,而在团队合作中,也绝不会只使用简单的驼峰或者是蛇形,团队需要形成一定的属于自己的命名规范,这样才能做到团队成员高效合作。
可读性规则
以上介绍的是语法规范,但实际上我们在命名时不仅要注意语法上的规范,对于代码本身的可读性也需要注意,单词是否需要缩写,单词的排列顺序是怎样的,这些也值得我们探讨。
“编程本身就是一种社会活动,大部分的编程活动都是人与人协作的过程”。
在人类的社交活动中,明确才是第一目标。尽可能做到顾名思义才是代码命名存在的本身意义。所以,在代码的构造中,我们也应该遵循以下几点:
语义清晰
使用带有语义的命名,能够让维护代码的人更容易理解和修改代码。
名副其实
名称不需要注释补充就可见其含义、用途
排斥不必要废话
不要写多余的废话或者容易让人混淆的命名。比如"customerObject"和"customer", 这种就是意义混杂的废话。莫名其妙多出来的Object实际上并无意义。我们区分应该使用特定的可以区分的命名来描述它。
避免非公认缩写/简写——可读性>简短性
为了能让命名更加易懂和易读,尽量不要缩写/简写单词,除非这些单词已经被公认可以被这样缩写/简写。像链表,LinkList,你当然不能写成LLst等,晦涩难懂。
使用可读的名称
我们要规避过于罕见或者根本不常用的单词,甚至是自己创造的词语,那更是禁忌,毕竟代码是给人读的,而不是什么过于抽象的艺术作品。
类名和对象名应该是名词或名词短语
方法名应当是动词或动词短语
如postPayment、deletePage或save。属性访问器、修改器和断言应该根据其值命名,并依Javabean标准加上get、set和is前缀。
每个系列词组中选一个词作为标志词,代表它属于这个组。
在同类型的词中,就应该只有一个命名,例如链表,那么操作的命名中都应该带有LT(LinkList),例如:
LTPushFront LTInsert LTInit
专业化、术语化、精简化
我们应该尽量用术语(CS术语,算法,数学术语)命名;尽量用那些计算机科学(Computer Science,CS)术语、算法名、模式名、数学术语;尽量使用问题涉及领域的术语
避免使用非专业术语;避免使用中文,拼音;避免命名过长
提高代码规范
在遵循以上规则和了解了基本的命名方法之后,我们可以通过以下方式或途径来提高自己的代码规范,养成一定的好习惯之后,那么优秀的命名必定会不请自来。
1.不断试错,不断润色
把你的变量名问别人,无论是懂代码还是不懂,他说的和你想的大致不差,就照着这个方向去修改,去润色。直到别人能很清晰地读懂你的命名——毕竟命名的第一要事就是可读性。
2.学习企业/大型项目命名
看别的大型项目源码是怎么起名的,哪些变量名使用的频率最高,或者关注大厂的命名有哪些值得学习的地方,站在巨人的肩膀上,往往能看得更远。
3.参考命名网站
例如Codelf、CHTML等等命名网站,参考它们的好处是通常它们集合了大部分大众适用,使用率高的命名方式,那么也就可以保证命名的容错率,从而了解大致的命名方向和命名规则。
后序
“如果讨论一下就知道,如果名称改得更好,那大家真的会感激你。多数时候我们并不记忆类名和方法名。我们使用现代工具对付这些细节,好让自已集中精力于把代码写得就像词句篇章、至少像是表和数据结构(词句并非总是呈现数据的最佳手段)。改名可能会让某人吃惊,就像你做到其他代码改善工作一样。别让这种事阻碍你的前进步伐。”
代码的命名规范不过是Clean Code之中的一环,当我们锻炼好了我们作为一个程序员的思想维度和代码感,那么对于好的命名也就信手拈来了,毕竟,最终的结果取决于你自己。