返回總目錄 本小節目錄 Split Temporary Variable(分解臨時變數) Remove Assignments to Parameters(移除對參數的賦值) Remove Assignments to Parameters(移除對參數的賦值) 6.6Split Temporary ...
本小節目錄
6 Split Temporary Variable(分解臨時變數)
概要
你的程式有某個臨時變數被賦值超過一次,它既不是迴圈變數,也不被用於收集計算結果。
針對每次賦值,創造一個獨立、對應的臨時變數。
動機
臨時變數有各種不同的用途。
1、迴圈變數;
2、結果收集變數;
3、保存一段冗長代碼的運算結果,便於稍後使用。
其中第三種情況的臨時變數應該只被賦值一次。如果它們被賦值超過一次,就意味著它們在函數中承擔了一個以上的責任。如果臨時變數承擔了多個責任,它就應該被分解為多個臨時變數,每個變數只承擔一個責任。同一個臨時變數承擔兩件不同的事情,會令代碼閱讀者糊塗。
範例
double GetTotalCost() { double result = 0; double money = _chickMoney + _chipMoney; result += money; money = _cocoaMoney + _coffeeMoney; result += money; return result; }
可以看到在這個範例中,臨時變數money被賦值兩次。並且它沒有做到累積結果的作用,累積結果給了result。所以,我們需要做重構,讓這個變數的意圖變的更加明確。
所以我們第一步,尋找這個變數第一次聲明的地方,並且將他改名,然後修改在第二次賦值之前的所有引用點,並且在第二次賦值處進行重新聲明:
double GetTotalCost() { double result = 0; double mealMoney = _chickMoney + _chipMoney; result += mealMoney ; double money = _cocoaMoney + _coffeeMoney; result += money; return result; }
現在,新的臨時變數只承擔原先money的第一個責任。而且我們在原先money變數第二次被賦值處重新聲明瞭money。然後,繼續處理money臨時變數的第二次賦值。
double GetTotalCost() { double result = 0; double mealMoney = _chickMoney + _chipMoney; result += mealMoney ; double drinkMoney = _cocoaMoney + _coffeeMoney; result += drinkMoney ; return result; }
可以看到,我們完成了變數的重構之後,函數對於臨時變數之前的money的困惑已經沒有了,整體因為變數名字的本身使得邏輯更加清晰。
如果在這裡你的代碼還是比較複雜的話,可以盡情使用其他的重構手法。
小結
這個重構手法的重點在於:臨時變數不是用於迴圈變數和結果收集,但卻被賦值超過兩次,那就對它進行分解,使其每次只承擔一個責任。
7 Remove Assignments to Parameters(移除對參數的賦值)
概要
代碼對一個參數進行賦值。
以一個臨時變數取代該參數的位置。
動機
首先要明確這裡“對參數賦值”的意思。如果你把一個名為foo的對象作為參數傳給某個函數,那麼“對參數賦值”就意味著改變foo,使它引用另一個對象。如果在“被傳入對象”身上進行什麼操作,那是沒問題的。Java只採用按值傳遞的方式,而C#分為值傳遞和引用傳遞,關於C#的值傳遞和引用傳遞,請看我的另一篇文章,或者自行百度。
int test(int a) { if (a > 50) { a = 1; } return a; }
這個就違反了這個原則,因為你對傳入參數進行重新賦值會讓代碼閱讀者產生歧義,降低了代碼的清晰度。他們搞不清甚至看不懂你參數到底代表什麼含義,甚至會對你這個參數的穩定性表示擔憂。
在值類型按值傳遞的情況下,對參數的任何修改,都不會對調用端造成任何影響。這個重構手法也是針對值類型按值傳遞的。
範例
int GetDiscount(int inputVal, int quantity, int yearToDate) { if (inputVal > 50) { inputVal -= 2; } if (quantity > 100) { inputVal -= 1; } if (yearToDate > 1000) { inputVal -= 4; } return inputVal; }
以臨時變數取代對參數的賦值動作,得到以下代碼:
int GetDiscount(int inputVal, int quantity, int yearToDate) { int result=inputVal; if (inputVal > 50) { result-= 2; } if (quantity > 100) { result-= 1; } if (yearToDate > 1000) { result-= 4; } return result; }
小結
如果參數只表示“被傳遞進來的東西”,那麼代碼會很清晰。
To Be Continued...