以上是組織代碼順序的思路。下為總結內容。
1 代碼執行順序
通常我們對寫程式對資料操作都是取數,對資料進行計算,再列印。一段java示範代碼如下:
data = ReadData();
results = CalculateResultsFromData( data );
PrintResults( results );
這三個步驟思路非常清晰,說明了這幾個函數之間的耦合程度,和相互依賴性。除非什麼特殊情況發生,否則都會按照這個順序來執行。尤其在ABAP中,似乎都是這樣的順序。
再看一個例子:
revenue.ComputeMonthly();
revenue.ComputeQuarterly();
revenue.ComputeAnnual();
在以上代碼中先計算的是月份,接著是季度,最後是年份。這是一個常識,但是光從代碼中我們無法得出他們是否有耦合,是否應該按照這個特定順序執行。
再看一個VB例子:
ComputeMarketingExpense
ComputeSalesExpense
ComputeTravelExpense
ComputePersonnelExpense
DisplayExpenseSummary
從以上例子中也看不處這段代碼的執行順序有什麼特殊之處,也不知道如果改變語句的執行順序會怎樣。沒有任何的注釋,程式也沒有參數,可能都是直接對全域變數進行操作。所以這段代碼寫的並不好。
1.1 如何組織代碼執行順序
在上面的VB代碼中,應該有一個初始化函數,如InitializeExpenseData()。寫這個函數的目的是程式的結構更清晰,讓讀代碼的人知道了一個隱含的資訊,在調用其它函數之前,必須調用初始化函數。
使用函數參數讓函數依賴關係更加明顯。在以上VB代碼中,沒有資料在函數間傳遞,我們並不知道這些函數是否使用的是同樣的資料。這點在ABAP中也是,大多數代碼都直接對全域變數操作,應該在函數參數這修改下,即使是對全域變數操作,也要讓函式宣告清晰的告訴讀代碼的人這個函數用了哪些全域資料。經修改後的代碼如下:
expenseData = InitializeExpenseData( expenseData )
expenseData = ComputeMarketingExpense( expenseData )
expenseData = ComputeSalesExpense( expenseData )
expenseData = ComputeTravelExpense( expenseData )
expenseData = ComputePersonnelExpense( expenseData )
DisplayExpenseSummary( expenseData )
這些函數都是將expenseData作為輸入,和輸出。明確的表明了代碼的執行順序不能改變,這些代碼之間是有依賴關係的。
再看一個VB例子:
ComputeMarketingExpense( marketingData )
ComputeSalesExpense( salesData )
ComputeTravelExpense( travelData )
ComputePersonnelExpense( personnelData )
DisplayExpenseSummary( marketingData, salesData, travelData, personnelData )
可以看到前4行代碼所使用的參數並不相同,所以更改它們的執行順序是可以的,應為它們之間並沒有依賴關係。但是最後一行代碼的執行必須在末尾處。
有時難以通過參數表明函數執行順序的依賴,那麼就通過注釋,不過注釋應該是最後的選擇,self-document code才是最佳。
1.2 檢查代碼的依賴性
如果對代碼安全性要求很高的話,可能還需要其他的方法來檢查代碼的執行順序。如設定布爾變數,來判斷是否已經執行了相關的操作。
2. 代碼順序對程式無影響的情況
總有這樣的一種情況,代碼的執行順序對程式不會有影響。那就始終抱著一個原則:Keep related actions together.有一個c++的例子如下:
MARKETING_DATA *marketingData = new MARKETING_DATA;
SALES_DATA *salesData = new SALES_DATA;
TRAVEL_DATA *travelData = new TRAVEL_DATA;
travelData.ComputeQuarterly();
salesData.ComputeQuarterly();
marketingData.ComputeQuarterly();
salesData.ComputeAnnual();
marketingData.ComputeAnnual();
travelData.ComputeAnnual();
salesData.Print();
delete salesData;
travelData.Print();
delete travelData;
marketingData.Print();
delete marketingData;
上面的代碼例子可以看到,如果你想對marketingData是怎樣計算的,你必須從第一行開始看起,直到最後一行。下面是一個組織的較好的例子:
MARKETING_DATA *marketingData = new MARKETING_DATA;
marketingData.ComputeQuarterly();
marketingData.ComputeAnnual();
marketingData.Print();
delete marketingData;
SALES_DATA *salesData = new SALES_DATA;
salesData.ComputeQuarterly();
salesData.ComputeAnnual();
salesData.Print();
delete salesData;
TRAVEL_DATA *travelData = new TRAVEL_DATA;
travelData.ComputeQuarterly();
travelData.ComputeAnnual();
travelData.Print();
delete travelData;
這段代碼將相似的操作局部化了,這樣在關注與一個變數的時候,只用關注與這一點,不用從頭到尾尋找代碼。對於組織的不好的代碼,我深有體會。一個幾千行的代碼,我看了半天不知道它到底幹什麼,每次看到這樣的代碼我就重寫的衝動,而不是修改。
局部化了之後,可以將每一部分都能寫成一個function,更加模組化。
2.2 組織代碼優劣的判斷
如何判斷將一段程式碼群組織的清晰易懂了?一個簡單的方法就是將相關聯的語句用方框畫出來,如果沒有重疊,那麼代碼是不錯的。
如果程式碼群組織的不好,畫出的方框很可能是這樣的:
這樣思路就比較混亂,看代碼的人也很鬱悶,需要花較長的時間才能讀懂代碼。