小酌重構系列[5]——為布爾方法命名
概述
當一個方法包含大量的布爾參數時,方法是很脆弱的,由此還可能會產生兩個問題:
2. 給方法的使用者造成一定困擾,可能會產生一些預期之外的結果
本文要介紹的重構策略“為布爾方法命名”,可以有效地避開這兩個問題。
為布爾方法命名
大量布爾參數帶來的問題
下圖中的SomeClass的SomeMethod包含3個布爾參數,如果沒有注釋,調用者根本不知道3個布爾參數所代表的含義。
即使為這個方法提供了詳細的注釋,調用者也很容易在調用時出錯。
調用者一不小心寫錯了其中一個參數,就可能產生非預期的行為。
在實際的業務處理中,也許你僅用這3個參數處理2~3個業務Case。
但這個方法有3個布爾參數,相當于為調用者提供了8種調用Case!
難道你的程序需要提供8種Case嗎?完全沒有必要,因為其他幾種Case可能根本不會發生!
var obj = new SomeClass(); obj.SomeMethod(false, false, false); // way1 obj.SomeMethod(false, true, false); // way2 obj.SomeMethod(false, true, true); // way3 obj.SomeMethod(false, false, true); // way4 obj.SomeMethod(true, true, true); // way5 obj.SomeMethod(true, false, false); // way6 obj.SomeMethod(true, true, false); // way7 obj.SomeMethod(true, false, true); // way8
這好比上個世紀生產的電視機遙控器,幾十個按鍵,用戶沒有說明書根本就不知道怎么用!
對于用戶來說,一個遙控器用來調節頻道、音量就足夠了。
給用戶太多地選擇反而不是一件好的事情,用戶會因太多的選擇而徘徊不定,永遠不要給用戶提供繁雜的使用方式!
重構策略
“為布爾方法命名”這種策略,意在將一些布爾參數提取出來,結合適當的方法命名來取代布爾參數。
接下來,進入我們的示例環節,用實際的示例來說明這個重構策略。
示例
重構前
CreateAccount()方法用于創建賬戶,它提供了4個參數,后3個參數都是布爾類型的。
public class BankAccount
{
public void CreateAccount(Customer customer, bool withChecking, bool withSavings, bool withStocks)
{
// do work
}
}
如果你是這個方法的調用者,在你腦袋中或許會蹦出8種調用方式,但你知道該如何調用嗎?
我不知道你們的答案是什么,我的答案是:不明確。
重構后
仔細分析“創建銀行賬戶”這項業務,我們發現“創建賬戶”只會產生兩種Case。
PS: 你去銀行開戶時,需要驗證你的身份信息。
2. 驗證并創建賬戶,同時存入初始儲蓄金額
PS: 你去銀行開戶時,當身份信息驗證通過后,你可以向銀行卡中存入一部分初始金額。
我們提供了2個方法來實現這2種Case,這2個方法使用具有意義的命名,并將原有的CreateAccount()方法用private修飾限制其訪問性。
public class BankAccount
{
public void CreateAccountWithChecking(Customer customer)
{
CreateAccount(customer, true, false);
}
public void CreateAccountWithCheckingAndSavings(Customer customer)
{
CreateAccount(customer, true, true);
}
private void CreateAccount(Customer customer, bool withChecking, bool withSavings)
{
// do work
}
}
重構以后,調用者只能使用CreateAccountWithChecking()和CreateAccountWithCheckingAndSavings()方法,這兩個方法的名稱也很容易讓人知道其含義。
使用Flags
這條建議來自于園友@blackbob。C#的Flags特性允許enum類型使用組合值。
public class BankAccount
{
private readonly IList<CreateAccountOptions> _createAccountOptionList = new[]
{
CreateAccountOptions.WithChecking,
CreateAccountOptions.WithChecking | CreateAccountOptions.WithSavings
};
public void CreateAccount(Customer customer, CreateAccountOptions option)
{
if (!_createAccountOptionList.Contains(option))
{
throw new ArgumentException("Invalid create account option", "option");
}
// do work
}
}
[Flags]
public enum CreateAccountOptions
{
None = 0,
WithChecking = 1,
WithSavings = 2,
WithStocks = 4
}
class Program
{
static void Main(string[] args)
{
BankAccount bankAccount = new BankAccount();
Customer customer1 = new Customer();
// 驗證并創建賬戶
bankAccount.CreateAccount(customer1, CreateAccountOptions.WithChecking);
// 驗證并創建賬戶,同時存入初始儲蓄金額
Customer customer2 = new Customer();
bankAccount.CreateAccount(customer2, CreateAccountOptions.WithChecking | CreateAccountOptions.WithSavings);
}
}
使用Flags枚舉,除了例子中的兩種Case外,還可能產生一些其他的組合。
為了防止用戶濫傳參數,我們可以在執行CreateAccount操作前先做個參數驗證。
本文鏈接: 文章作者:keepfool 文章出處:http://www.rzrgm.cn/keepfool/ 如果您覺得閱讀本文對您有幫助,請點一右下角的“推薦”按鈕,您的“推薦”將是我最大的寫作動力!歡迎看官們轉載,轉載之后請給出作者和原文連接。

當一個方法包含大量的布爾參數時,方法是很脆弱的,由此還可能會產生兩個問題:
1. 方法不容易被理解
2. 給方法的使用者造成一定困擾,可能會產生一些預期之外的結果
本文要介紹的重構策略“為布爾方法命名”,可以有效地避開這兩個問題。

浙公網安備 33010602011771號