變量名的力量(P259)
1.選擇好變量名的注意事項
一個好的變量名是可讀的、易記的和恰如其分的。
1)最重要的命名注意事項
為變量命名時最重要的考慮事項是,該名字要完全、準确地描述出該變量所代表的事物。獲得好名字的一種實用技巧就是用文字表達變量所代表的是什麼。通常,對變量的描述就是最佳的變量名。 名字應該盡可能的明确。像x、temp、i這些名字都泛泛得可以用于多種目的,它們并沒有像應該的那樣提供足夠資訊,是以通常都是命名上的敗筆。
2)以問題為導向
一個好記的名字反映的通常都是問題,而不是解決方案。
3)最适當的名字長度
太長 numberOfPeopleOnTheUsOlympicTeam
numberOfSeatsInTheStadium
maximumNumberOfPointsInModernOlympics
太短 n,np,ntm
n,ms,nsisd
m,mp,max,points
正好 numTeamMembers,teamMemberCount
numSeatsInStadium,seatCount
teamPointsMax,pointsRecord
4)作用域對變量名的影響
當你把一個變量名取得很短的時候,如i,這一長度本身就對該變量做出了一些說明——該變量代表的是一個臨時的資料,它的作用域非常有限。
對位于全局命名空間中的名字加以限定詞
在那些不支援命名空間或者包的語言裡,可以為全局可見的類加上帶有子系統特征的字首。使用者接口部分的雇員類可能命名為uiEmployee,資料庫部分的雇員類可能命名為dbEmployee,這樣做能把全局命名空間的命名沖突降到最低。
5)變量名中的計算值限定詞
如果你要用類似于Total、Sum、Average、Max、Min、Record、String、Pointer這樣的限定詞來修改某個名字,那麼請記住把限定詞加到名字的最後。
6)變量名中的常用對仗詞
- begin/end
- first/last
- locked/unlocked
- min/max
- next/previous
- old/new
- opened/closed
- visible/invisible
- source/target
- source/destination
- up/down
2.為特定類型的資料命名
1)為循環下标命名
對于一般的循環,可以用i、j和k這種約定俗成的名字:但是對于長循環、嵌套循環,就很容易忘記i的意義,這麼處理可以提高可讀性:for( i = firstItem; i < lastItem; i++){ data[ i] = 0; }
for( teamIndex = 0; teamIndex < teamCount; teamIndex++){ for( eventIndex = 0; eventIndex < eventCount[teamIndex]; eventIndex++){ score[ teamIndex][ eventIndex] = 0; } }
2)為狀态變量命名
為狀态變量取一個比flag更好的名字。 下面例子中标記的命名都很差:像statusFlag = 0x80這樣的語句是反映不出這段代碼能做什麼的,除非是自己親自寫的,或者有文檔告訴你。下面是作用相同但更為清晰的代碼:if( flag) ... if( statusFlag & 0x0F) ... if( printFlag == 16) ... if( computeFlag == 0) ... flag = 0x1; statusFlag = 0x80; printFlag = 16; computeFlag = 0;
if( dataReady) ... if( characterType & PRINTABLE_CHAR) ... if( reportType == ReportType_Annual) ... if( recalcNeeded == false) ... dataReady = true; characterType = CONTROL_CHARACTER; reportType = ReportType_Annual; recalcNeeded = false;
如果你發現自己需要猜測某段代碼的含義的時候,就該考慮為變量重新命名。
3)為臨時變量命名
通常,臨時變量是一個信号,表面程式員還沒有完全把問題弄清楚。而且,由于這些變量被正式地賦予了一種“臨時”狀态,是以程式員會傾向于比其他變量更為随意地對待這些變量,進而增加了出錯的可能。 警惕“臨時”變量:這樣儲存一個變量是很不錯的,特别是當這一結果還會被随後兩次用到的時候。但是名字temp卻絲毫也沒有反應該變量的功能。下面的例子顯示了一種更好的做法:temp = sqrt( b^2 - 4*a*c); root[0] = ( -b + temp ) / ( 2 * a ); root[1] = ( -b + temp ) / ( 2 * a );
discriminant = sqrt( b^2 - 4*a*c); root[0] = ( -b + discriminant ) / ( 2 * a ); root[1] = ( -b + discriminant ) / ( 2 * a );
4)為布爾變量命名
下面是一些格外有用的布爾變量名:
- done
- error
- found
- success或ok
這樣命名的重點在于給布爾變量賦予隐含“真/假”含義的名字,對于類似status這樣的名字,你什麼也說不出來。
5)為枚舉類型命名
在使用枚舉類型的時候,可以通過使用組字首,如Color_等來明确表示該類型的成員都同屬于一個組Public Enum Color Color_Red Color_Green Color_Blue End Enum Public Enum Planet Planet_Earth Planet_Mars Planet_Venus End Enum Public Enum Month Month_January Month_February ... Month_December End Enum
6)為常量命名
在具名常量時,應該根據該常量所表示的含義,而不是該常量所具有的數值為該抽象事物命名。比如FIVE = 6.0就顯得太可笑了。
3.命名規則的力量
1)為什麼要有規則
關鍵之處在于,采用任何一項規則都要好于沒有規則。規則可能是武斷的。命名規則的威力并非來源于你所采取的某個特定規則,而是來源與以下事實:規則的存在為你的代碼增加了結構,減少了你需要考慮的事情。
2)何時采用命名規則
- 當多個程式員合作開發一個項目時
- 當你計劃把一個程式轉交給另一位程式員來修改和維護的時候
- 當你所在組織中的其他程式員評估你寫的程式的時候
- ...
3)正式程度
對于微小的、用完即棄的項目而言,實施嚴格的規則可能就太沒必要了。對于多人協作的大型項目而言,無論是在開始階段還是貫穿整個程式的生命周期,正式規則都是成為提高可讀性的必不可少的輔助手段。
4.非正式命名規則
-
區分變量名和子程式名字
本書所采用的命名規則要求變量名和對象名以小寫字母開始,子程式以大寫字母開始:variableName對RoutineName()。
- 區分類和對象
//方案一:通過大寫字母開頭區分類型和變量 Widget widget; LongerWidget longerWidget; //方案二:通過全部大寫區分類型和變量 WIDGET widget; LONGERWIDGET longerWidget; //方案三:通過給類型加“t_”字首區分類型和變量 t_Widget Widget; t_LongerWidget LongerWidget; //方案四:通過給變量加“a”字首區分類型和變量 Widget aWidget; LongerWidget aLongerWidget; //方案五:通過對變量采用更明确的名字區分類型和變量 Widget employeeWidget; LongerWidget fullEmployeeWidget;
-
辨別全局變量
在全局變量之前加上g_字首,比如g_RunningTotal
-
辨別成員變量
在成員變量之前加上m_字首
-
辨別類型聲明
C++的慣用方法是把類型名全部大寫——例如COLOR和MENU。不過這樣可會增加與命名預處理常量發生混淆的可能。為了避免這種情況,可以為類型名增加t_字首,如t_Color和t_Menu。
-
辨別具名常量
在VB裡,具名常量可能是一個函數的傳回值,可以給常量增加c_字首區分。
在C++和Java裡則全部用大寫,以及有可能的話用下劃線來分隔單詞,如:RECS_MAX
- 辨別枚舉類型的元素
-
在不能保證輸入參數隻讀的語言裡辨別隻讀參數
如const,final,nonmodifiable等字首
-
格式化命名以提高可讀性
用大小寫和下劃線“_”分隔字元
1)與語言相關的命名規則的指導原則(P275)2)混合語言程式設計的注意事項
- C的命名規則
- C++的命名規則
- Java的規則
- Visual Basic的命名規則
在混合語言環境中程式設計時,可以對命名規則作出優化以提高整體的一緻性和可讀性——即使意味着優化後的規則會與其中某種語言所用的規則相沖突。
5.标準字首
1)使用者自定義類型(UDT)縮寫
UDT縮寫 含義 ch 字元(Character,這裡指的字元不是指C++中的字元,而是指文字處理程式可能用于表示一份文檔中的字元的資料類型) doc 文檔(Document) pa 段落(Paragraph) scr 螢幕區域(Screen region) sel 選中範圍(Selection) wn 窗體(window) 當使用UDT時,應該像這樣資料聲明:
CH chCursorPosition
SCR scrUserWorkspace
DOC docActive
...
2)語義字首
語義字首比UDT更進一步,它描述了變量或者對象是如何使用的。一組段落的下标可以命名為iPa;cPa是相應的計數值,段落的總數量。
語義字首 含義 c 數量(Count,如記錄、字元或者其他東西的個數) first 數組中需要處理的第一個元素 g 全局變量 i 數組的下标 last 數組中需要處理的最後一個元素 lim 數組中需要處理的元素的上限(表示的是一個數組中并不存在的上界,即last+1) m 類一級的變量 max 數組或者其他種類清單中絕對的最後一個元素,反映的是數組本身 min 同上 p 指針(pointer)
3)标準字首的優點
除了具備命名規則所能提供的一般意義上的優點外,标準字首還為你帶來了另外一些好處。由于很多名字都已經标準化了,是以你在一個程式或者類内需要記憶的名字更少了。
6.建立具備可讀性的短名字
從某種程度上說,要求使用短變量名是早期計算的遺留物。而在現代語言如C++、Java和VB裡面,實際上你可以建立任何長度的名字,幾乎沒有任何理由去縮短具有豐富含義的名字。
1)縮寫的一般指導原則
其中的一些原則彼此沖突,是以不要試圖同時應用所有的原則。
- 使用标準的縮寫(列在字典中的那些常見縮寫)
- 去掉所有非前置元音(computer變成cmptr,screen變成scrn,temp變成tmp)
- 去掉虛詞and,or,the等
- 去除無用的字尾——ing,ed等
- 使用每個單詞的第一個或前幾個字母
- ...
2)語音縮寫
有些人倡導基于單詞的發音而不是拼寫來建立縮寫,于是skating就變成了sk8ing,before變成了b4,execute變成了xqt。太難猜,不提倡。
3)有關縮寫的評論
- 不要用從每個單詞删除一個字元的方式來縮寫
- 縮寫要一緻
- 建立你能讀出來的名字
- 避免使用容易看錯或者讀錯的字元組合
- 使用辭典來解決命名沖突
- 在代碼裡用縮寫對照表解釋極短的名字的含義
- 在一份項目級的“标準縮寫”文檔中說明所有的縮寫
本原則中展現出來的核心問題,是友善編寫代碼的同時友善閱讀代碼兩種理念之間的差異。上面的方法很明顯會帶來代碼編寫時的麻煩,但是程式員們在整個項目生命周期裡會把更多的時間花在閱讀代碼而不是編寫代碼之上。這種方法提高了閱讀代碼的友善性。 名字對于代碼讀者的意義比對作者更重要。
7.應該避免的名字
- 避免使用令人誤解的名字或縮寫
- 避免使用具有相似含義的名字
- 避免使用具有不同含義但卻有相似名字的變量
- 避免使用發音相近的名字
- 避免在名字中使用數字
- 避免在名字中拼錯單詞
- 避免實用英語中常常拼錯的單詞
- 不要僅靠大小寫來區分變量名
- 避免使用多種自然語言
- 避免使用标準類型、變量和子程式的名字
- 不要使用與變量含義完全無關的名字
- 避免在名字中包含易混淆的字元