软件中随处可见命名,所以命名的规范性至关重要
2.1 介绍
- 做好各种命名,是整洁代码的第一步
2.2 名副其实
- 变量、函数或类的名称应该已经答复了所有问题 ,如果没有满足这个条件,说明这段代码不够整洁
2.2.1 Bad Example
- 这段代码在算法上并没有什么问题,即没有混乱的格式,也没有复杂的表达式
- 但即使如此简短的代码,在仔细阅读过后,也无法准确得知其用处
- 这就是下面这个例子的问题所在:代码中变量、函数的名称都不具备任何意义,这导致了代码的模糊度极高
public List<int[]> getThem() {
List<int[]> list1 = new ArrayList<int[]>;
for (int[] x : theList) {
if (x[0] == 4) {
list1.add(x);
}
}
return list1;
}
2.2.2 Good Example
- 这段稍加优化后的代码,依旧没有一行注释
- 但在稍加阅读后,就可以得知这段代码的用处是要从棋盘中获取被标记的单元格
- 优化后的代码,其实没有修改任何代码逻辑,只是单纯的替换掉了变量和函数的名称
- 这足以说明 有意义的命名 对一段代码的重要性
public List<int[]> getFlaggedCells() {
List<int[]> flaggedCells = new ArrayList<int[]>;
for (int[] cell : gameBoard) {
if (cell[STATUS_VALUE] == FLAGGED) {
flaggedCells.add(cell);
}
}
return flaggedCells;
}
2.2.3 Great Example
- 进一步将可能导致语义不清的数组、常量用对象替换,即可以让代码进入更高的层次
- 这其实已经到了重构的范畴
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = new ArrayList<Cell>;
for (Cell cell : gameBoard) {
if (cell.isFlagged()) {
flaggedCells.add(cell);
}
}
return flaggedCells;
}
2.3 避免误导
- 必须避免留下隐藏代码本意的错误线索
- 应当避免使用与代码本意相悖的词
- 不要使用变量类型来作为变量的名称
accountList
应该写成accounts
- Tips:不过其实我觉得如果是将其他类型转化为 String 类型使用,在名称后面加一个 Str 倒是个不错的选择
Date createTime
写成createTimeStr
int[] codes
写成codeStrs
- 不要使用相似度太高的名称,这样反而更难以区分
2.4 做有意义的区分
- 如果变量、函数的名称必须不同,那么两者的意思也应该不同才对
- 首先要做到不要用数字或废话命名,数字很好懂,那么废话是什么?
ProductInfo
和ProductData
中的 Info 和 Data ,相对于Prodcut
本身就是废话- 因为这根本就是一种没意义的区分
- 要区分名称,就要以读者能够鉴别不同之处的方式来区分
2.5 使用读的出来的名称
- 人类进化到大脑中有那么大的一块地方用来处理语言,若不善加利用,实在是种耻辱
- 意思就是要多记单词,要不然等到给变量、函数或类命名的时候就只能使用自造词了
2.6 使用可搜索的名称
- 单字母名称和数字常量有个问题,就是很难再一大篇文字中找出来
- 名称长短与其作用域大小相对应,例如使用在 for 循环中的下标变量,使用 i 、j 或 k ,就无伤大雅
2.7 避免使用编码
- 这一点我觉得也不一定,例如在前端的常量 JS 中,使用
ERROR_CODE_404
以及ERROR_CODE_400
就可以很好的区分 - 不过肯定也有更好的命名方法,例如根据 404 和 400 的具体含义来命名为
NO_PAGE
和BAD_REQUEST
2.7.1 匈牙利标记法
- 就是将数据类型标记在名称上
- 现在不论是对于 Java 还是 Javascript ,都不推荐了
2.7.2 成员前缀
- 应当把类和函数做的足够小,消除对成员前缀的需要
2.7.2.1 Bad Example
- 随着代码中名称前缀的增多,最终人们会学会无视前缀,所以前缀实际上就是毫无意义的内容
public class Part {
private String m_dsc;
void setName(String name) {
m_dsc = name;
}
}
2.7.2.2 Good Example
- 直接使用有意义的名称,同时遵循 Getter/Setter 规则进行赋值
public class Part {
private String description;
void setDescription(String description) {
this.description = description;
}
}
2.7.3 接口和实现
- 例如接口
UserService
的实现类是UserServiceImpl
2.8 避免思维映射
- 名称的指向应该明确,明确是王道
- 专业程序员善用其能,编写其他人能理解的代码
2.9 类名
- 类名和对象应该是名词或名词短语
- 例如:Customer 、WikiPage
- 类名不应该是动词
- 例如:Go 、Run
2.10 方法名
- 方法名应该是动词或动词短语
- 并且依据 Javabean 标准为访问器 、修改器或断言增加 get 、set 或 is 前缀
2.11 别扮可爱
- 如果名称太耍宝,那就只有同作者一般有幽默感的人才能记得住
- 要记住 言到意到,意到言到
2.12 每个概念对应一个词
- 给每个抽象概念选一个词,让它能直接表达你的想法
- 现在的各种 IDE 都能做到直接展现某个对象能调用的方法列表,但是不难发现这些方法列表中是不会显示每个方法对应注释的
- 所以最直接的的理解方法含义的方式,就是为方法指定一个直观的名称
- 当然,每个方法的注释依旧还是要写的
2.13 别用双关语
- 避免将同一单词用于不用目的
- 我们想要那种大众化的平装书模式,不想要那种学者挖地三尺才能明白的学院派模式
2.14 使用解决方案领域名称
- 对于针对场景的变量、函数或类,优先选择通用的技术性的名称
2.15 使用源自所涉问题领域的名称
- 如果无法找到通用的技术性的名称,则优先选择针对场景自身最适用的名称
- 要做到 分离解决方案领域和问题领域 的概念
2.16 添加有意义的语境
- 良好命名的类、函数和变量之间应该形成一个关联关系
2.17 不要添加没用的语境
- 只要短名称足够清楚,就应该优先使用短名称,精确才是命名的要点
2.18 最后的话
- 勇敢的去重构