返回總目錄 6.4Replace Temp with Query(以查詢取代臨時變數) 概要 你的程式以一個臨時變數保存某一表達式的運算結果。 將這個表達式提煉到一個獨立函數中。將這個臨時變數的所有引用點替換為對函數的調用。此後,新函數就可以被其他函數使用。 動機 臨時變數的問題在於:只在當前函數可 ...
6.4Replace Temp with Query(以查詢取代臨時變數)
概要
你的程式以一個臨時變數保存某一表達式的運算結果。
將這個表達式提煉到一個獨立函數中。將這個臨時變數的所有引用點替換為對函數的調用。此後,新函數就可以被其他函數使用。
動機
臨時變數的問題在於:只在當前函數可見。如果你在同類的別的地方訪問這個變數,你就必須重新寫表達式來獲取這個變數,這樣的話你就會在不經意間讓你的函數變得複雜起來。如果將臨時變數替換為一個查詢,那麼同類中所有函數都可以獲得這份信息。
所以如果你想要使用Extract Method,那麼Replace Temp with Query是必不可少的一個步驟。而我們前面介紹的Inline Temp其實是這個手法的一部分,兩者的區別在於Inline Temp已經有了表達式自身,只需要做簡單的替換就可以,需要用表達式本身把臨時變數給去掉。而Replace Temp with Query更加全面,裡面包含了提煉表達式到函數本身,然後替換引用點(Inline Temp)。如果你把所有的臨時變數都替換為一個查詢,你的類的結構和邏輯將非常清晰,這樣將更加有利於你的重構和進行優化。
範例
假設有以下簡單函數:
double GetPrice() { int basePrice = _quantity * _itemPrice; double discountFactor; if (basePrice > 1000) { discountFactor = 0.95; } else { discountFactor = 0.98; } return basePrice * discountFactor; }
我們現在將basePrice 和discountFactor這兩個臨時變數都替換掉。
先來替換basePrice,將basePrice右側表達式提煉出來,然後使用Inline Temp將basePrice的所有引用點都替換掉,並且把basePrice臨時變數的聲明去掉。
現在代碼變成這樣:
double GetPrice() { double discountFactor; if (GetBasePrice() > 1000) { discountFactor = 0.95; } else { discountFactor = 0.98; } return GetBasePrice() * discountFactor; } private int GetBasePrice() { return _quantity * _itemPrice; }
再以類似的方法提煉出GetDiscountFactor();
private double GetDiscountFactor() { if (GetBasePrice() > 1000) { return 0.95; } return 0.98; }
最終代碼是這樣的。
double GetPrice() { return GetBasePrice() * GetDiscountFactor(); } private double GetDiscountFactor() { if (GetBasePrice() > 1000) { return 0.95; } return 0.98; } private int GetBasePrice() { return _quantity * _itemPrice; }
可以明顯的看到,這個重構手法對於函數本身來說,提高了清晰度,也讓我們進行後期重構能夠更加便捷。
小結
我們常常在迴圈中用臨時變數保存累加信息。如果是這種情況的話,我們可以將整個迴圈都提煉出來。如果在迴圈中要累加好幾個值,那麼就應該針對每個累加值重覆一遍迴圈。這樣,就可以很方便的將所有臨時變數都替換為查詢。
當然,這樣一來,我們可能擔心性能問題。本來我定義一個臨時變數只需要查詢一次,現在我每次都要去做查詢。這個我們完全不必擔心。重構的目的是讓程式更加清晰,有了更加清晰的程式之後再具體做優化也不遲,況且根據二八原則,僅僅這條查詢語句倘若你系統真的出現了性能問題也不大可能,如果實在是因為這條語句,你也可以把變數再放回去。
To Be Continued...