在自然語言中,雙重否定表示肯定。但是在程式中,雙重否定會降低代碼的可讀性,使程式不易理解,容易產生錯覺。 人通常是用“正向思維”去理解一件事情的,使用雙重否定的判斷,需要開發者以“逆向思維”的方式去理解它的含義。 另外,在寫程式時,"!"符號很容易被疏忽和遺漏,一不小心則會編寫出錯誤的代碼,從而產生... ...
避免雙重否定
在自然語言中,雙重否定表示肯定。但是在程式中,雙重否定會降低代碼的可讀性,使程式不易理解,容易產生錯覺。
人通常是用“正向思維”去理解一件事情的,使用雙重否定的判斷,需要開發者以“逆向思維”的方式去理解它的含義。
另外,在寫程式時,"!"符號很容易被疏忽和遺漏,一不小心則會編寫出錯誤的代碼,從而產生bug。
所以,在程式中,我們應當儘量避免使用雙重否定。
優惠券是否未被使用?
還是以線上商城給用戶發放優惠券為例,由於優惠券的初始狀態是未被使用的,所以設計人員將優惠券的使用狀態設計為IsUnused。
/// <summary> /// 優惠券 /// </summary> public class Coupon { /// <summary> /// 是否未被使用 /// </summary> public bool IsUnused { get; set; } }
這樣設計會帶來兩個小問題
- IsUnused表示“優惠券是否未被使用”,這句話本身是比較拗口的,開發人員需要“逆向思維”去理解它的含義。
- 在寫程式時,如果要判斷“優惠券已經被使用”,則需要編寫比較繞彎的程式
// 如果優惠券已經被使用了 if (!coupon.IsUnused) { // 業務邏輯 }
這段代碼如果沒有第1行的註釋,是比較難於理解的,也許你是用以下方式理解的。
理解這段代碼看起來頗為費勁,我們應該換種方式來理解它。
因此,將屬性設計為IsUsed更為合適。
/// <summary> /// 優惠券 /// </summary> public class Coupon { /// <summary> /// 是否被使用 /// </summary> public bool IsUsed { get; set; } }
編寫的判斷語句,可讀性良好,也易於理解。
// 如果優惠券已經被使用了 if (coupon.IsUsed) { // 業務邏輯 }
PS:設計程式畢竟不是唱Rap,你沒必要把自己饒進去了,又把別人也繞進去,大家都能輕易讀懂的代碼才可能是好的代碼。
示例
重構前
這段代碼使用!customer.IsNotFlagged
判斷“客戶賬戶被標記”,如果沒有註釋,這個判斷就比較難理解。
public class Order { public void Checkout(IEnumerable<Product> products, Customer customer) { // 如果客戶賬戶被標記了 if (!customer.IsNotFlagged) { // 記錄錯誤並返回 return; } // 正常的訂單處理流程 } } public class Customer { public decimal Balance { get; private set; } public bool IsNotFlagged { get { return Balance < 30m; } } }
程式本意是為了表達一個肯定的語義——“如果客戶賬戶是被標記的”,既然如此,我們何不直接用肯定的語義來表示它呢?
重構後
重構後,代碼讀起來就更加直觀了,也很容易被理解。
public class Order { public void Checkout(IEnumerable<Product> products, Customer customer) { // 如果客戶賬戶被標記了 if (customer.IsFlagged) { // 記錄錯誤並返回 return; } // 正常的訂單處理流程 } } public class Customer { public decimal Balance { get; private set; } public bool IsFlagged { get { return Balance >= 30m; } } }
小結
在設計bool類型的屬性時,不僅要表達清楚它所表示的業務含義,還應當考慮編寫代碼時的複雜性,儘量避免使用雙重否定。
【關註】keepfool