概述 當條件判斷語句較為複雜時(有多個不同的檢查項),就像下麵這幅圖所表示的,會使得代碼的可讀性會大打折扣,也難以清晰地傳達判斷意圖。 再者,當判斷邏輯變更時,我們不得不去修改if語句裡面的判斷代碼。如果判斷寫得有問題,則會影響方法的正確性,也會給該方法的單元測試帶來一些障礙。 我們可以根據檢查項是... ...
概述
當條件判斷語句較為複雜時(有多個不同的檢查項),就像下麵這幅圖所表示的,會使得代碼的可讀性會大打折扣,也難以清晰地傳達判斷意圖。
再者,當判斷邏輯變更時,我們不得不去修改if語句裡面的判斷代碼。
如果判斷寫得有問題,則會影響方法的正確性,也會給該方法的單元測試帶來一些障礙。
我們可以根據檢查項是否需要參數來封裝條件,如果檢查項不需要參數,則可以將其提取為屬性;如果需要參數,則將其提取為方法。
本文要講的重構策略“封裝條件”是基於“提取方法”這個重構策略的。
示例
重構前
這個示例中,PerformCoolFunction()方法的if條件檢查項有三個。
public class RemoteControl { private string[] Functions { get; set; } private string Name { get; set; } private int CreatedYear { get; set; } public string PerformCoolFunction(string buttonPressed) { // Determine if we are controlling some extra function // that requires special conditions if (Functions.Length > 1 && Name == "RCA" && CreatedYear > DateTime.Now.Year - 2) return "doSomething"; } }
我們可以不必去理解這個複雜判斷的含義,從代碼層面看,這個判斷有三個問題:
- 可讀性較差,同時也意味著較差的維護性
- 增加了編寫PerformCoolFunction方法單元測試的複雜度,我們不得不為if判斷單獨追加一個測試case
- if判斷所用的參數和PerformCoolFunction方法無關
重構後
這三個檢查項構成的條件表達式可讀較差,所以將這個條件表達式提取為一個方法。這樣在做條件判斷時就變成了if (HasExtraFunctions),代碼的可讀性由此增強。另外,我們通過提取出來的條件判斷方法名稱,也可以準確地洞悉判斷的意圖。
public class RemoteControl { private string[] Functions { get; set; } private string Name { get; set; } private int CreatedYear { get; set; } private bool HasExtraFunctions { get { return Functions.Length > 1 && Name == "RCA" && CreatedYear > DateTime.Now.Year - 2; } } public string PerformCoolFunction(string buttonPressed) { // Determine if we are controlling some extra function // that requires special conditions if (HasExtraFunctions) return "doSomething"; } }
用bool變數代替判斷條件
這個示例的判斷條件只有3個,而且每個條件的判斷語句比較短。
如果遇到一些判斷語句較長,且條件個數很多的判斷,我們該怎麼辦?
我的建議是用bool變數代替判斷條件。
偷個懶,我們仍然用上面的例子來示範這種方式:
public class RemoteControl { private string[] Functions { get; set; } private string Name { get; set; } private int CreatedYear { get; set; } private bool HasExtraFunctions { get { // 首碼c表示condition bool cFuncLen = (Functions.Length > 1); bool cName = (Name == "RCA"); bool cCreatedYear = (CreatedYear > DateTime.Now.Year - 2); return cFuncLen && cName && cCreatedYear; } } public string PerformCoolFunction(string buttonPressed) { // Determine if we are controlling some extra function // that requires special conditions if (HasExtraFunctions) return "doSomething"; } }
小結
封裝複雜判斷的精髓是“提取方法”,即將複雜的判斷邏輯提取為方法。
【關註】keepfool