第二章主要说一下命名的一些要遵循的小标准。
1. 名副其实
1.变量、函数或类的名称应该已经答复了所有的大问题,如果名称需要注释来补充,那就不算名副其实
int d; // 消逝的时间,以日计
名称d什么也没说明,没有引起对时间消逝的感觉,更别说以日计了。应选择指明了计量对象和计量单位的名称
int elapsedTimeInDays;
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;
2.代码的模糊度:即上下文在代码中未被明确体现的程度
体现本意的名称能让人更容易理解和修改代码。比如开发一种扫雷游戏,在盘面上找出已标记的格子。每个格子用一个数组表示,数组的0下标为其状态,记录是否被标记
public List<int[]> getThem(){
List<int[]> list1 = new ArrayList<int[]>();
for(int[] x : theList)
if (x[0] == 4)
list1.add(x);
return list1;
}
难以看懂上述代码要做什么事,问题在于其代码的模糊度:即上下文在代码中未被明确体现的程度。
在阅读上述代码时需要了解类似以下问题的答案:
- theList中是什么类型的东西?
- theList零下标条目的意义是什么?
- 值4的意义是什么?
- 我怎么使用返回的列表?
问题的答案应该体现在代码中。如零下标条目是一种状态值,而4表示“已标记”,使用有意义的名称后,
改进如下:
public List<int[]> getFlaggedCells(){
List<int[]> flaggedCells = new ArrayList<int[]>();
for(int[] cell : gameBoard)
if (cell[STATUS_VALUE] == FLAGGED)
flaggedCells.add(cell);
return flaggedCells;
}
进而不用数组表示单元格,而是另写一个类代表每个单元格,该类包括一个isFlagged函数,则重构后代码如下:
只要简单改一下名称,就能轻易知道发生了什么。
2. 避免误导
1.程序员必须避免留下掩藏代码本意的错误线索。应当避免使用与本意相悖的词
别用accountList来指称一组账号,除非它真的是List类型。用accountGroup、bunchOfAccounts甚至accounts都更好。
2.提防使用不同之处较小的名称。
如XYZControllerForEfficientHandlingOfStrings和XYZControllerForEfficientStorageOfStrings。
3.以同样的方式拼写出同样的概念才是信息,拼写前后不一致就是误导。
要注意使用小写字母i和大写字母O作为变量名,看起来像“壹”和“零”
int a = 1;
if(O == 1){
a = O1;
}else{
1 = O1;
}
3. 做有意义的区分
1.名称必须相异,那其意思也应该不同。避免添加数字或废话区分。
如果程序员只是为满足编译器或解释器的需要而写代码,就会制造麻烦。若因为同一作用范围内两样不同的东西不能重名而改掉其中一个的名称,光是添加数字系列远远不够。
错误例子:
public static void copyChars(char[] a1, char[] a2){
for(int i = 0; i < a1.length; i++){
a2[i] = a1[i];
}
}
如果参数名改为source和destination,这个就会像样许多。
2.废话是另一种没意义的区分。
假设你有一个Product类,如果还有一个ProductInfo或ProductData类,那它们的名称虽然不同,意思却无区别
getActiveAccount();
getActiveAccounts();
getActiveAccountInfo();
moneyAmount与money
customerInfo与customer
accountData与account
theMessage与message
3.只要体现出有意义的区分,使用a和the这样的前缀就没错。
4.废话都是冗余。
Variable一词记录不应当出现在变量名中,Table一词永远不应当出现在表名中
4. 使用读得出来的名称
编程是一种社会活动,标识符名称也要能读得出来。
比如日期:用generationTimestamp,而不要使用genymdhms。
5. 使用可搜索的名称
1.单字母名称和数字常量有个问题,就是很难在一大篇文字中找出来
长名称胜于短名称,搜得到的名称胜于用自造编码代写就的名称。名称长短应与其作用域大小相对应
for (int j = 0; j < 34; j++){
s += (t[j]*4)/5;
}
int readDaysPerIdealDay = 4;
final int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int j = 0; j < NUMBER_OF_TASKS; j++){
int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
int realTaskWeeks = realTaskDays / WORK_DAYS_PER_WEEK;
sum += realTaskWeeks;
}
6. 避免使用编码
1.把类型或作用域编进名称里面,徒然增加了解码的负担
phoneNumber phoneString;
//类型变化时,名称并不变化!
2.也不必用m_前缀来标明成员变量,应当把类和函数做得足够小,消除对成员前缀的需要。
public class Part{
private String m_dsc; // The Textual description
void setName(String name){
m_dsc = name;
}
}
public class Part{
private description;
void setDescription(String description){
this.description = description;
}
}
人们会很快学会无视前缀或后缀,只看到名称中有意义的部分。代码读得越多,眼中越没有前缀。最终前缀变成了不入眼的废料。
3.不加修饰的接口,不要用前导字母
ShapeFactory
IShapeFactory
而要用
ShapeFactory
ShapeFactoryImp
7. 避免思维映射
1.不应当让读者在脑中把你的名称翻译为他们熟知的名称,单字母变量名就是个问题
比如你用r 来代表一个循环变量名。但是别人却认为是不包含主机名和图式的url。因此单字母名称并不是一个好选择
2.专业程序员了解,明确是王道
8. 类名
1.类名和对象名应该是名词或名词短语,类名不应当是动词
Customer、WikiPage、Account和AddressParser,避免使用Manager、Processor、Data或Info这样的类名。类名不应当是动词。
9. 方法名
1.方法名应该是动词或动词短语。
如postPayment、deletePage或save。
属性访问器、修改器和断言应该根据其值命名,并依Javabean标准加上get、set和is前缀
2.可以考虑将相应构造器设置为private,强制使用这种命名手段
重载构造器时,使用描述了参数的静态工厂方法名。例如,
Complex fulcrumPoint = Complex.FromRealNumber(23.0);
通常好于
Complex fulcrumPoint =new Complex(23.0);
10. 别扮可爱
1.言到意到,意到言到.不使用俚语
比如谁知道HolyHandGrenada (圣手手雷)函数是干什么的,没错这个名字挺伶俐,但是不过DeleteItems或许是更好的名字。
11. 每个概念对应一个词
例如使用fetch、retrieve和get来给在多个类中的同种方法命名(仅单独使用这几个单词),得耗费大把时间浏览各个文件头及前面的代码。
再如统一使用controller、manager或driver中的一个。
12. 别用双关语
1.避免将同一单词用于不同目的
比如用add表示两数相加,那么要写一个把数字加入集合中的方法时,方法名不应为add,而改用insert或append更合适。
2.应尽力写出易于理解的代码,把代码写得让别人能一目尽览而不必殚精竭虑地研究
13. 使用解决方案领域名称
1.尽管用那些计算机科学术语、算法名、模式名、数学术语
14. 使用源自所涉问题领域的名称
1.如果不能用程序员熟悉的术语来给手头的工作命名,就采用从所涉问题领域而来的名称
2.优秀的程序员和设计师,其工作之一就是分离解决方案领域和问题领域的概念
15. 添加有意义的语境
1.你需要用有良好命名的类、函数或名称空间来放置名称,给读者提供语境。
如下代码中,number、verb和pluralModifier这三个变量要遍鉴函数才能推断其含义:
private void printGuessStatistics(char candidate, int count){
String number;
String verb;
String pluralModifier;
if (count == 0){
number = "no";
verb = "are";
pluralModifier = "s";
} else if (count == 1) {
number = "l";
verb = "is";
pluralModifier = "";
} else {
number = Integer.toString(count);
verb = "are";
pluralModifier = "s";
}
String guessMessage = String.format(
"There %s %s %s%s", verb, number, candidate, pluralModifier);
print(guessMessage);
}
改进
要分解这个函数,需要创建一个名为GuessStatisticsMessage的类,这样变量在定义上变作了GuessStatisticsMessage的一部分。语境的增强让算法能够通过 分解为更小的函数而变得干净利落。
public class GuessStatisticsMessage{
private String number;
private String verb;
private String pluralModifier;
public String make(char candidate, int count){
createPluralDependentMessageParts(count);
return String.format(
"There %s %s %s%s", verb, number, candidate, pluralModifier);
}
private void createPluralDependentMessageParts(int count){
if (count == 0){
threAreNoLetters();
} else if (count == 1){
thereIsOneLetter();
} else {
threAreManyLetters(count);
}
}
private void thereAreManyLetters(int count){
number = Integer.toString(count);
verb = "are";
pluralModifier = "s";
}
private void thereIsOneLetter() {
number = "l";
verb = "is";
pluralModifier = "";
}
private void thereAreNoLetters(){
number = "no";
verb = "are";
pluralModifier = "s";
}
}
2.如果没这么做,给名称添加前缀就是最后一招了
16. 不要添加没用的语境
1.只要短名称足够清楚,就要比长名称好。
例如给类名添加工程名缩写的前缀。
对于Address类的实体来说,accountAddress和customerAddress都是不错的名称,不过用在类名上就不太好了。
Address是个好类名。如果需要MAC地址、端口地址和Web地址相区别,会考虑使用PostalAddress、MAC和URL。这样的名称更为精确,而精确正是命名的要点。
17. 最后的话
取好名字最难的地方在于需要良好的描述技巧和共有文化背景,用好以上规则,加油,你可以的!
18. 参考文献
https://www.jianshu.com/p/c44eca6add14
https://zhuanlan.zhihu.com/p/37639722
https://www.cnblogs.com/stoneniqiu/p/4815259.html
本公众号分享自己从程序员小白到经历春招秋招斩获10几个offer的面试笔试经验,其中包括【Java】、【操作系统】、【计算机网络】、【设计模式】、【数据结构与算法】、【大厂面经】、【数据库】期待你加入!!!
1.计算机网络----三次握手四次挥手
2.梦想成真-----项目自我介绍
3.你们要的设计模式来了
4.一字一句教你面试“个人简介”
5.接近30场面试分享