[獨自murmur]謹慎使用全域變數
全域變數的濫用,會造成程式維護上的困難。
根據Code Complete2的Ch5,講到設計耦合性低的系統,應小心使用全域變數,
全域變數會帶來許多程式設計難題。
1. function在操作時,不知道還有其他function也在全域操作。
2. function雖然知道其他也在操作,但是不知道它們進行的操作。
舉例來說,(下面這段code,一樣是腦袋中的虛擬碼,不過我盡量讓它符合設計的格式了)
這個例子是按了Calculate的按鈕,要把畫面上ItemPrice1~ItemPrice3的資料加起來,計算時要符合折扣,然後存入DB。
{
integer total=0;
integer discountBound=300;
private void PaymentTotal(integer vPayment)
{
total+=PaymentDiscount(vPayment);
}
//超過discountBound打8折
private void PaymentDiscount(integer vPayment)
{
if(vPayment>discountBound)
{return vPayment*0.8;}
else
{return vPayment;}
}
//假設UI有限制textbox的格式需為整數且必KEY
protected void Calculate_Click(object sender, ImageClickEventArgs e)
{
PaymentTotal(this.ItemPrice1.text);
PaymentTotal(this.ItemPrice2.text);
PaymentTotal(this.ItemPrice3.text);
SavatoDB();
}
//將總金額存入DB
private void SavatoDB()
{
//把total直接存到DB...
}
}
這個例子在計算最後的總金額,是透過全域變數total來當暫存的結果。
可以發現,在每個function處理時,其實對每個function自己來說,並不知道是否有其他function會影響到total這個變數。
甚至,會出現「要先執行functionA()之後,才能執行functionB(),最後的結果才會符合我們需要的邏輯」這類的情況。
也就是function與function之間出現相依性(耦合變高)。
這對偵錯與維護都會造成很大的不便。
今天我存檔之後,發現total錯了,(通常會是「明明之前可以,為什麼現在不行」的情況)
我得花很大的力氣去找「到底那邊改變了我的total」,
一切的原因就在於,我的total是全域變數,我不知道在整個執行過程中,到底被誰改變,到底被誰影響,
或是我這次的增加或修改的程式碼,呼叫的順序錯了等等千奇百怪的原因,都可能會造成我在算總金額時的意外。
那全域變數要怎麼用?
小的只是隻沒寫多少程式的菜鳥,所以只能提供自己的一點小經驗。
1.初始化後不再改變,這種可以使用。
2.改用區域變數+參數來寫。
第一種情況,因為值assign的動作只有一次,也很有可能是初始化的值,所以不用擔心出問題時找不到地方。
例如,我們整支頁面程式都要讀取到Session("UserID")的值,
那我可能宣告一個全域變數叫userID,在Page_Load()的時候,將Session("UserID")的值assign給userID。
之後要使用Session("UserID")就用userID的值即可。
這樣的好處是不必每次都讀取session,且花的effort只是個小小的變數記憶體空間。
之後維護時倘若userID要多額外的判斷條件才能決定,也只需要修改userID初始化的定義即可。
第二種情況,
則是在function裡面用區域變數+參數,來取代全域變數的功能。
例如
//假設UI有限制textbox的格式需為整數且必KEY protected void Calculate_Click(object sender, ImageClickEventArgs e)
{
integer total=0;
total+=PaymentDiscount(this.ItemPrice1.text);
total+=PaymentDiscount(this.ItemPrice2.text);
total+=PaymentDiscount(this.ItemPrice3.text);
SavatoDB(total);
}
//將總金額存入DB
private void SavatoDB(integer vTotal)
{
//把vTotal直接存到DB...
}
如此一來,SavatoDB不會被全域變數影響,
Calculate_Click也不會被全域變數所影響,
且能達到原本需要的功能。
希望這個粗糙的例子,可以表達出我要解釋的概念。
如果你的code裡面,出現了一堆function或void,是沒有參數的,
或void有達到output的功用,卻不需要return值,
請檢查看看,是不是因為使用全域變數來達到這樣的功能。
貪圖「這次」的方便,會造成debug或維護上工時增加的最大原兇。
blog 與課程更新內容,請前往新站位置:http://tdd.best/