2.1、 介绍
在给变量、函数、参数、类、包的命名、jar包、war包、ear文件的命名都需要一个好的命名。
2.2、名副其实(见名知意)
变量
// 不推荐
int d ; //消失的时间,以日计
// 推荐
int elapsedTimeInDays;
例子:选择体现本意的名称能让人更容易理解和修改代码。下列代码的目的何在?
// 不推荐
public List<int[]> getThem( List<int[]> theList){
List<int[]> list1 = new ArrayList<int[]>();
for(int[] x : theList){
if(x[0] ==4){
list1.add(x);
}
}
return list1;
}
// 存在的问题点
// 1、theList 零下标的意义是什么?
// 2、值4的意识是什么?
// 3、我怎么使用返回的列表?
// 4、这个方法是要处理什么的?
问题的答案没体现在代码段中,可那就是它们该在的地方。比方说,我们在开发一种扫雷游戏,我们发现,盘面是名为theList的单元格列表,那就将其名称改为gameBoard。
盘面上每个单元格都用一个简单数组表示。我们还发现,零下标条目是一种状态值,而该种状态值为4表示“已标记”。只要改为有意义的名称,代码就会得到相当程度的改进:
public List<int[]> getFlaggedCells() {
List<int[]> flaggedCells = newArrayList<int[]>();
for (int[] cell : gameBoard)
if (cell[STATUS_VALUE] == FLAGGED)
flaggedCells.add(cell);
return flaggedCells;
}
注意,代码的简洁性并未被触及。运算符和常量的数量全然保持不变,嵌套数量也全然保持不变。但代码变得明确多了。
还可以更进一步,不用int数组表示单元格,而是另写一个类。该类包括一个名副其实的函数(称为isFlagged),从而掩盖住那个魔术数[9]。于是得到函数的新版本:
public List<Cell> getFlaggedCells() {
List<Cell> flaggedCells = newArrayList<Cell>();
for (Cell cell : gameBoard)
if (cell.isFlagged())
flaggedCells.add(cell);
return flaggedCells;
}
只要简单改一下名称,就能轻易知道发生了什么。这就是选用好名称的力量。
2.3、避免误导
1、避免使用与本意是相悖的词。
例子1、hp、aix 因为他们都是unix平台或类 Unix平台的专有名称。
例子2、别用词义容易误导的名称:
定义一个变量名称为一组帐号的变量。
不推荐 String accountList=null; // 容易误导成是List类型。
推荐 accountGroup 、bunchOfAccounts 或accounts.
例子3、别用外形相似两个词
XYZControllerForEfficientHandingStrings
XYZControllerForEfficientStorageOfStrings
形相似的字母和数字组合。
int a=1;
if(o==1)
a=o1;
else
1=01;
2.4、做有意义的区分
public static void copyChars(char a1[],char a2[]){
for(int i=0;i<a1.length;i++){
a2[i]=a1[i];
}
}
推荐
public static void copyChars(char source[],char destination[]){
for(int i=0;i<source.length;i++){
destination[i]=source[i];
}
}
2.5、使用读得出来的名称
class DtaRcrd102{
private Date genymdhms;
private Date modymdhms;
private final String pszqint ="102";
}
推荐
class Customer{
private Date generationTimestamp;
private Date modificationTimestamp;
private final String recordId="102";
}
2.6、使用可搜索的名称
String s ="";
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] *realDaysPerIdealDay;
int realTaskWeeks = (realdays /WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}
2.7、避免使用编码
String phoneString;
成员前缀
private Strig m_dsc;
接口实现
推荐
接口名称
ShapeFactory
实现类名称
ShapeFactoryImp
不推荐
IShapeFactory 前导字母I被滥用到了说好听点是干扰,说难听点根本就是废话的程度
2.8、避免思维映射
不应当让读者在脑中把你的名称翻译为他们熟知的名称。这种问题经常出现在选择是使用问题领域术语还是解决方案领域术语时。
计数器:
单字母变量名就是个问题。在作用域较小、也没有名称冲突时,循环计数器自然有可能被命名为i或j或k。(但千万别用字母l!)这是因为传统上惯用单字母名称做循环计数器。然而,在多数其他情况下,单字母名称不是个好选择;
聪明程序员和专业程序员之间的区别在于,专业程序员了解,明确是王道。专业程序员善用其能,编写其他人能理解的代码。
自己的问题:有时候想给一个变量起一个名词,但是不知道怎么起,然后就习惯性的写 temp。
2.9、类名称
2.10、方法名
2.11、添加有意义的语境
private static void printGuessStatistics(String candidate,int count){
String number;
String verb;
String pluralModifier;
if(count ==0){
number="no";
verb="are";
pluralModifier="s";
}else if(count==1){
number="1";
verb="is";
pluralModifier="";
}else{
number=count+"";
verb="are";
pluralModifier="s";
}
String guessMessage =String.format("there %s %s %s", number,verb,candidate,pluralModifier);
System.out.println(guessMessage);
}
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", number,verb,candidate,pluralModifier);
}
private void createPluralDependentMessageParts(int count){
if(count==0){
thereAreNoTettle();
}else if (count==1){
thereAreOneLetter();
}else{
thereAreManyLitters(count);
}
}
private void thereAreNoTettle(){
number ="no";
verb="are";
pluralModifier="s";
}
private void thereAreOneLetter(){
number ="1";
verb="is";
pluralModifier="";
}
private void thereAreManyLitters(int count){
number =count+"";
verb="are";
pluralModifier="s";
}
2.17、不要添加没用的语境
设若有一个名为“加油站豪华版”(Gas Station Deluxe)的应用.
你在GSD应用程序中的记账模块创建了一个表示邮件地址的类,然后给该类命名为GSDAccountAddress。稍后,你的客户联络应用中需要用到邮件地址,你会用GSDAccountAddress吗?这名字听起来没问题吗?在这17个字母里面,有10个字母纯属多余和与当前语境毫无关联。
只要短名称足够清楚,就要比长名称好。别给名称添加不必要的语境。
对于Address类的实体来说,accountAddress和customerAddress都是不错的名称,不过用在类名上就不太好了。Address是个好类名。如果需要与MAC地址、端口地址和Web地址相区别,我会考虑使用PostalAddress、MAC和URI。这样的名称更为精确,而精确正是命名的要点。
2.18、总结
取好名字最难的地方在于需要良好的描述技巧和共有文化背景。与其说这是一种技术、商业或管理问题,还不如说是一种教学问题。其结果是,这个领域内的许多人都没能学会做得很好。
我们有时会怕其他开发者反对重命名。如果讨论一下就知道,如果名称改得更好,那大家真的会感激你。多数时候我们并不记忆类名和方法名。我们使用现代工具对付这些细节,好让自己集中精力于把代码写得就像词句篇章、至少像是表和数据结构(词句并非总是呈现数据的最佳手段)。改名可能会让某人吃惊,就像你做到其他代码改善工作一样。别让这种事阻碍你的前进步伐。
不妨试试上面这些规则,看你的代码可读性是否有所提升。如果你是在维护别人写的代码,使用重构工具来解决问题。效果立竿见影,而且会持续下去。
最后拿一个例子来结束第二章的学习
不建议
publicstatic String testableHtml(
PageData pageData,
boolean includeSuiteSetup
) throwsException {
WikiPage wikiPage = pageData.getWikiPage();
StringBuffer buffer = new StringBuffer();
if (pageData.hasAttribute("Test")) {
if (includeSuiteSetup) {
WikiPage suiteSetup =
PageCrawlerImpl.getInheritedPage(
SuiteResponder.SUITE_SETUP_NAME, wikiPage
);
if (suiteSetup != null) {
WikiPagePath pagePath =
suiteSetup.getPageCrawler().getFullPath(suiteSetup);
String pagePathName = PathParser.render(pagePath);
buffer.append("!include -setup .")
.append(pagePathName)
.append("\n");
}
}
WikiPage setup =
PageCrawlerImpl.getInheritedPage("SetUp", wikiPage);
if (setup != null) {
WikiPagePath setupPath =
wikiPage.getPageCrawler().getFullPath(setup);
String setupPathName = PathParser.render(setupPath);
buffer.append("!include -setup .")
.append(setupPathName)
.append("\n");
}
}
buffer.append(pageData.getContent());
if (pageData.hasAttribute("Test")) {
WikiPage teardown =
PageCrawlerImpl.getInheritedPage("TearDown", wikiPage);
if (teardown != null) {
WikiPagePath tearDownPath =
wikiPage.getPageCrawler().getFullPath(teardown);
String tearDownPathName = PathParser.render(tearDownPath);
buffer.append("\n")
.append("!include-teardown .")
.append(tearDownPathName)
.append("\n");
}
if (includeSuiteSetup) {
WikiPage suiteTeardown =
PageCrawlerImpl.getInheritedPage(
SuiteResponder.SUITE_TEARDOWN_NAME,
wikiPage
);
if (suiteTeardown != null) {
WikiPagePath pagePath =
suiteTeardown.getPageCrawler().getFullPath (suiteTeardown);
String pagePathName = PathParser.render(pagePath);
buffer.append("!include -teardown .")
.append(pagePathName)
.append("\n");
}
}
}
pageData.setContent(buffer.toString());
return pageData.getHtml();
}
搞懂这个函数了吗?大概没有。有太多事发生,有太多不同层级的抽象。奇怪的字符串和函数调用,混以双重嵌套、用标识来控制的if语句等,不一而足。
publicstatic String renderPageWithSetupsAndTeardowns(
PageData pageData, boolean isSuite
) throwsException {
boolean isTestPage = pageData.hasAttribute("Test");
if (isTestPage) {
WikiPage testPage = pageData.getWikiPage();
StringBuffer newPageContent = new StringBuffer();
includeSetupPages(testPage, newPageContent, isSuite);
newPageContent.append(pageData.getContent());
includeTeardownPages(testPage, newPageContent, isSuite);
pageData.setContent(newPageContent.toString());
}
return pageData.getHtml();
}
第二章:有意义的命名总结:
1、有意义,名副其实:降低代码的模糊度,明确说明代码的用途;
2、避免误导:accountList的类型最好就是List;
3、避免使用多个不同之处较小的名称;
4、避免使用字母l和O,因为它们像数字1和0;
5、做有意义的区分,只有意义不同时才使用不同的名字;
6、废话是无意义的区分,是冗余;
7、使用可搜索的名称:用宏定义数字比直接用数字好,避免使用单字母变量和数字常量;
8、不必使用带类型的匈牙利标记法;
9、避免成员变量使用类名前缀;
10、类名和对象名一般都是名词和名词短语;
11、方法名一般是动词和动词短语;get,set,is前缀;
12、使用解决方案领域内的名称;
13、添加有意义的语境:使用有意义的前缀,创建一个类并将变量声明为成员变量;
14、命名要精确:不要添加无意义的语境;