避免雙重否定
在自然語言中,雙重否定表示肯定。但是在程序中,雙重否定會降低代碼的可讀性,使程序不易理解,容易產生錯覺。
人通常是用“正向思維”去理解一件事情的,使用雙重否定的判斷,需要開發者以“逆向思維”的方式去理解它的含義。
另外,在寫程序時,"!"符號很容易被疏忽和遺漏,一不小心則會編寫出錯誤的代碼,從而產生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類型的屬性時,不僅要表達清楚它所表示的業務含義,還應當考慮編寫代碼時的復雜性,盡量避免使用雙重否定。


