步步为营 .NET 代码重构学习笔记 三、内联方法(Inline Method)
一、Inline? Method
概述
一個函數,其本體(method body)應該與其名稱(method name)同樣清楚易懂.
動機(Motivation)
以簡短的函數表現動作意圖,這樣會使代碼更清晰易讀.但有時候你會遇到某些函數.其內部代碼和函數名稱同樣清晰易讀.也可能你重構了該函數,使得其內容和其名稱變得同樣清晰.果真如此,你就應該去掉這個函數,直接使用其中代碼,間接可能帶來幫助,但非必要的間接性總是讓人不舒服.
作法(Mechanics)
1、檢查函數,確定它不具多態性(is not ploymorphic)
如果subclass繼承了這個函數,就不要將此函數inline化。因為subclass無法覆寫(override)一個根本不存在的函數。
2、找出這個函數的所有被調用點。
3、將這個函數的所有被調用點都替換為函數本體(代碼)。
4、刪除該函數的定義。
示例
public class Inline{public string GetUserInfo(int Age){return MoreThenTen(Age) ? "spring yang" : null;}public bool MoreThenTen(int Age){return Age > 10;}}?
改為:
public class Inline{public string GetUserInfo(int Age){return Age>10 ? "spring yang" : null;}}?
二、Inline Temp
概述
一個臨時變量,只被一個簡單表達式賦值一次,而它妨礙了其它重構手法。
動機(Motivation)
Inline Temp多半是作為Replace Temp with Query的一部分來使用。惟一單獨使用Inline Temp的情況是:你發現某個臨時變量被賦予某個函數調用的返回值。一般來說,這樣的臨時變量不會有任何危害,你可以放心地把它留在那兒。但如果這個臨時變量妨礙了其它重構手法---例如Extract Method,就應該將它inline化。
作法(Mechanics)
1、如果這個臨時變量并未被聲明為final,那就將它聲明為final,然后編譯。
這可以檢查該臨時變量是否真的只被賦值一次。
2、找到該臨時變量的所有引用點,將它們替換為為臨時變量賦值的語名中的等號右側表達式。
3、每次修改后,編譯并測試。
4、修改完所有引用點之后,刪除該臨時變量的聲明式和賦值語名。
示例
public class Inline{public double GetUserSalary(string name){double salary = UserSalary(name);return salary * 5;}}?
改為:
public class Inline{public double GetUserSalary(string name){return UserSalary(name) * 5;}}?
三、Replace Temp with Query
概述
程序以一個臨時變量(temp)保存某一表達式的運算結果。將這個表達式提煉到一個獨立函數(查詢式,query)中。將這個臨時變量的所有(被引用點)替換為對新函數的調用。新函數可被其它函數使用。
動機(Motivation)
臨時變量的問題在于,它們是暫時的,而且只能在所屬函數內使用。由于臨時變量只有在所屬函數內才可見,所以它們會馬驅使你寫出更長的函數,因為只朋這樣你才能訪問到想要訪問的臨時變量。如果把臨時變量替換為一個楂詢式(query method),那么同一個class中的所有函數都將可以獲得這份信息。這將帶來極大幫助,使你能夠為這個class編寫更清晰的代碼。
作法(Mechanics)
1、找出只被賦值一次的臨時變量。
如果某個臨時變量被賦值超過一次,考慮使用Split Temporary Variable將它分割成多個變量。
2、將該臨時變量聲明為final。
3、編譯。
這可確保臨時變量的確只被賦值一次。
4、將對該臨時變量賦值的語名的等號右側部分提煉到一個獨立函數中。
首先將函數聲明為private,日后你可能會發現有更多class需要使用它,彼時你可輕易放松對它的保護。
確保提煉出來的函數無任何連帶影響,也就是說該函數并不修改任何對象內容。如果它有連帶影響,就對它進行Separate Query from Modifier。
示例
public double GetPrice(){int area = _width * _higth;double discount;if (area > 1000) discount = 0.9;else discount = 1;return area * discount;}?
改為:
public double GetPrice(){return GetArea() * GetDiscount();}public double GetDiscount(){double discount;if (GetArea() > 1000) discount = 0.9;else discount = 1;return discount;}public int GetArea(){return _width * _higth;}?
四、Introduce Explaining Variable
概述
將復雜表達式的結果放進一個臨時變量,以此變量名稱來解釋表達式用途。
動機(Motivation)
表達式有可能非常復雜而難以閱讀,臨時變量可以幫助你將表達式分解為比較容易管理的形式。
作法(Mechanics)
1、聲明一個final臨時變量,將待分解之復雜表達式中的一部分動作的運算結果賦值給它。
2、將表達式中的運算結果這一部分,替換為上述臨時變量。
如果被替換的這一部分在代碼中重復出現,你可以每次一個,逐一替換。
示例
double _width, _higth;public double GetPrice(){return _width * _higth - Math.Max(0, _width - 1000) * _higth * 0.03 + Math.Min(_width * _higth * 0.1, 100);}?
改為:
?
double _width, _higth;public double GetPrice(){return NormalPrice() - QuantityDiscount() + Shipping();}public double NormalPrice(){return _width * _higth();}public double QuantityDiscount(){return Math.Max(0, _width - 1000) * _higth * 0.03;}public double Shipping(){return Math.Min(NormalPrice() * 0.1, 100);}總結
將復雜表達式分解成清晰易讀的若干方法以使程序可讀性更強。
總結
以上是生活随笔為你收集整理的步步为营 .NET 代码重构学习笔记 三、内联方法(Inline Method)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 脚本宿主程序
- 下一篇: WPF获取鼠标相对于屏幕的绝对位置