返回總目錄 6.5Introduce Explaining Variable(引用解釋性變數) 概要 你有一個複雜的表達式。 將該複雜表達式(或其中一部分)的結果放進一個臨時變數,以此變數名稱來解釋表達式用途。 動機 有時候你會遇到一系列複雜的表達式連續運算的時候,這個時候你可能根本招架不住如此長或 ...
6.5Introduce Explaining Variable(引用解釋性變數)
概要
你有一個複雜的表達式。
將該複雜表達式(或其中一部分)的結果放進一個臨時變數,以此變數名稱來解釋表達式用途。
動機
有時候你會遇到一系列複雜的表達式連續運算的時候,這個時候你可能根本招架不住如此長或者是如此複雜的長函數。這個時候你可以通過引用臨時變數來儲存他們的結果,將這些長函數的結果分成一個個臨時變數來讓函數清晰化。這個重構手法在條件邏輯中用的比較多。
我們來看這樣一個條件判斷:
if(platform.ToUpper().IndexOf("MAC")>-1&&browser.ToUpper().IndexOf("IE")>-1&& wasInitialized()&&resize>0) { //do something }
是不是看上去暈暈的,不知道這個條件判斷是判斷什麼的?
我們用這個手法重構一下:
bool isMacOs = platform.ToUpper().IndexOf("MAC") > -1; bool isIEBrowser = browser.ToUpper().IndexOf("IE") > -1; bool wasResized = resize > 0; if (isMacOs && isIEBrowser && wasInitialized()&& wasResized) { //do something }
這樣代碼是不是很清晰。
範例
我們從一個簡單的計算開始:
double GetPrice() { return _quantity * _itemPrice - Math.Max(0, _quantity - 500) * _itemPrice * 0.05 + Math.Min(_quantity * _itemPrice * 0.1, 100.0); }
這段代碼很簡單,但是不好理解。可以進行Introduce Explaning Variable,將_quantity * _itemPrice的計算結果放進臨時變數中。
double GetPrice() { double basePrice = _quantity * _itemPrice; return basePrice - Math.Max(0, _quantity - 500) * _itemPrice * 0.05 + Math.Min(basePrice * 0.1, 100.0); }
再將折扣提煉出來。
double GetPrice() { double basePrice = _quantity * _itemPrice; double quantityDiscount = Math.Max(0, _quantity - 500) * _itemPrice * 0.05; return basePrice - quantityDiscount + Math.Min(basePrice * 0.1, 100.0); }
最後把運費計算提煉出來。最終代碼如下。
double GetPrice() { double basePrice = _quantity * _itemPrice; double quantityDiscount = Math.Max(0, _quantity - 500) * _itemPrice * 0.05; double shipping = Math.Min(basePrice * 0.1, 100.0); return basePrice - quantityDiscount + shipping; }
這裡雖然完成了,但是我們前面講過,臨時變數只在它所處的那個函數中才有意義,局限性較大,函數則可以在對象的整個生命中都有用,並且可以被其他對象使用。所以下麵我們使用Extract Method方法對剛剛的示例進行重構。同時我們也推薦使用這種方法。
運用Extract Method處理上述範例
同樣這樣一個函數:
double GetPrice() { return _quantity * _itemPrice - Math.Max(0, _quantity - 500) * _itemPrice * 0.05 + Math.Min(_quantity * _itemPrice * 0.1, 100.0); }
這一次我們把底價計算、批發折扣以及運費都提煉到一個新函數中。最終代碼如下:
double GetPrice() { return GetBasePrice() - GetQuantityDiscount() + GetShipping(); } private double GetQuantityDiscount() { return Math.Max(0, _quantity - 500) * _itemPrice * 0.05; } private double GetBasePrice() { return _quantity * _itemPrice; } private double GetShipping() { return Math.Min(GetBasePrice() * 0.1, 100.0); }
比較兩種手法
對比Extract Method和Introduce Explaining Variable這兩種手法生成的函數:
1、前者生成的函數更短,更清晰易懂,而後者則產生了大量的臨時變數,使函數變得更長;
2、前者生成了很多的獨立函數,如果想在外部訪問某個函數,直接調用就好,而後者得重新寫方法供其調用。
小結
我個人比較推薦Extract Method這種手法,因為同一對象中的任何部分,都可以根據自己的需要取用這些提煉出來的函數。一開始我們可以把函數聲明為private;如果其他對象需要它們,再釋放這些函數的訪問限制。
既然如此,那麼我們什麼時候使用Introduce Explaining Variable呢?在Extract Method這種手法需要花費更大工作量時。比如說,有一個擁用大量局部變數的演算法,這時候用Extract Method這個手法就不好處理。
To Be Continued...