這次準備連續(xù)寫三章的讀書筆記,因為這三章講得都是很基礎但又容易讓人忽略的細節(jié)問題。
第14章 組織直線型代碼
14.1 必須要有明確順序的語句。
設法組織代碼,使得依賴關系變得非常明顯。要非常明顯,非常是重點。例如下面的子程序就是具備明顯的依賴關系:
InitExpenseData(), ComputeExpenseData(), PrintComputeDataResult();后面的一個子程序總是需要依賴前面的子程序。
14.2 順序無關的語句
使代碼易于自上而下地閱讀。言下之意,就是要讓別人能夠按照常規(guī)邏輯順序閱讀你的代碼。比如下面的代碼:
MarketingData marketData;
marketData.ComputeQuarterly();
marketData.ComputeAnnual();
marketData.Print();
SalesData salesData;
salesData.ComputeQuarterly();
salesData.ComputeAnnual();
salesData.Print();
把相關的語句組織在一起。如果按照這種規(guī)定來編寫代碼,那么你的代碼看起來就一個代碼塊非常明顯地區(qū)別于其他代碼塊。
第15章 使用條件語句
這一章看似根本沒什么可以講,可是相信里面講得東西你不一定都能做到。
15.1 if語句
首先寫正常代碼路徑,再處理不常見情況。
把正常情況的處理放在if后面不要放在else后面??墒俏矣袝r候就顛倒過來了,因為一般錯誤處理情況代碼比較少,我放在前面,看起來自己覺得比較舒服??墒侨绻龅角短椎膇f,那就必須把正常情況放在if后面,因為這樣看起來邏輯性會比較強,可讀性也比較強。如:
if (status == Status_success)
{
// do something
if (status == Status_success)
{
// do something
if (status == Status_success)
{
// do something
}
else
{
// error control
}
}
else
{
// error control
}
}
else
{
// error control
}
if-then-else 語句
利用布爾函數(shù)調用簡化復雜的檢測。這點稍微有點經驗的人都知道,當你的if-else語句判斷需要做大量工作的時候,把判斷代碼抽象成一個布爾函數(shù)來調用,并把最常見的情況放在最前面,確保所有情況都考慮到了。
15.2 case語句
為case選擇最有效的順序。可以按字母、數(shù)字、執(zhí)行頻率來排列順序。
不要為了使用case而可以制造一個變量。東西都是如此,太刻意的結果往往是不好的結果。該用case則用case,不該用case就用if-else語句。
把default語句只用于檢查默認情況。有多少人寫switch-case不把default加進去?反正我是看過好幾次了,應該利用default來檢測錯誤,除非你真的考慮全面確定不會出現(xiàn)意外情況了,你確定??所以一般還是老老實實把default寫進去來檢測錯誤。
另外,避免復雜的case嵌套,別讓自己費腦子,更別讓維護你代碼的人有撞墻的沖動。
第16章 控制循環(huán)
16.1 選擇循環(huán)的種類
什么時候使用帶退出的循環(huán)?如果把循環(huán)條件檢測放在循環(huán)開始或者結束處,那就需要寫出一個半循環(huán)的代碼。
看看下面重復的代碼:
score = 0;
GetNextRating(&ratingIncrement);
rating = rating + ratingIncrement;
while (score < targetScore)
{
GetNextScore(&ScoreIncrement);
score= score+ ScoreIncrement;
GetNextRating(&ratingIncrement); // 重復代碼
rating = rating + ratingIncrement;
}
接下里使用半循環(huán)改寫,讓代碼易于維護:
score = 0;
while (true)
{
GetNextRating(&ratingIncrement);
rating = rating + ratingIncrement;
if (score < targetScore)
{
break;
}
GetNextScore(&ScoreIncrement);
score= score+ ScoreIncrement;
}
16.2 循環(huán)控制
避免循環(huán)出現(xiàn)錯誤發(fā)生的兩種方法:一是減少能影響循環(huán)各種因素的數(shù)量。也就是說,你的循環(huán)應該足夠的簡單。二是把循環(huán)內部看作一個子程序,把控制盡量放到循環(huán)體外,把循環(huán)執(zhí)行條件表達清楚。即:將循環(huán)看作一個黑盒子,外面的程序不知道循環(huán)里面做了什么,只知道循環(huán)的控制條件,這是最理想的情況。
進入循環(huán):
1. 只從一個位置進入。一般人都會這樣做,除非你嫌你的程序太簡單,搞一個goto進入到循環(huán)里;
2. 把初始化代碼放在循環(huán)前面。呃,這點和我做得不同,我一般是用到變量之前才進行初始化。但是書中談到要按照就近原則,把相關代碼放在一起;
3. 用while(true)表示無限循環(huán),或者for( ; ; )也可以;
4. 在適當情況多使用for循環(huán)。我也是傾向于for,因為for循環(huán)給人的感覺比較清晰,不容易出錯。
處理好循環(huán):
1. 用'{', '}'把循環(huán)語句括起來;
2. 避免空循環(huán)。這點我倒是沒注意,有時候就寫了空循環(huán),如下面:
while ( (ch = getchar()) != EOF)
{
;
}
實際上循環(huán)控制中包括了兩條語句,為了讓代碼更加清晰,可寫成:
do
{
ch = getchar();
} while (ch != EOF);
一個循環(huán)只做一件事:
符合UNIX的哲學:一個工具只做一件事,并且做好。
退出循環(huán):
使循環(huán)條件看起來很明顯。
不要為了終止循環(huán)而胡亂改動for循環(huán)的下標。有些程序員為了貪圖方便是會寫出這樣的代碼來的。比如下面:
for (int i = 0; i < 100; ++i)
{
if ( ... )
i = 100;
// ...
}
一旦你寫了for循環(huán),循環(huán)計數(shù)就不是你能控制的。如果你想對循環(huán)更多的控制,考慮改用while。
避免出現(xiàn)依賴于循環(huán)下標最終取值的代碼。我犯過這樣的錯誤,也是為了貪圖方便:
for (recordCount = 0; recordCount < MAX_RECORDS; ++recordCount)
{
if ( entry[recordCount] == testValue )
break;
}
if (recordCount < MAX_RECORDS)
return true;
else
return false;
這里通過recordCount來檢測循環(huán)是否執(zhí)行到最后面一次了。這樣的代碼也可理解,但是閱讀你代碼的人并一定能很快地理解你的代碼??紤]使用一個標志:
found = false;
for (recordCount = 0; recordCount < MAX_RECORDS; ++recordCount)
{
if (entry[recordCount] == testValue)
{
found = true;
break;
}
}
使用循環(huán)變量:
在嵌套循環(huán)中使用有意義的變量名來提高可讀性。太多的程序都是用i, j, k這樣的變量來寫了,我之前也曾這樣寫,上一個項目開始就沒這樣寫過了,取個好的名字總是能讓代碼看起來清爽很多。
把循環(huán)下標變量的作用域限制在本循環(huán)內。也就說,循環(huán)下標在這個循環(huán)內用到后,在循環(huán)外面都沒再用到了。例如上面那個利用循環(huán)下標來判斷是否找到了值的例子。
16.3 輕松創(chuàng)建循環(huán)——由內而外
其實我們大部分人對循環(huán)的思考還是這種由內而外的思維方式的,即先想這循環(huán)內要做什么事,具體哪些,邏輯順序排好了之后剩下的只是在外面加一個for或者while了。
END