if,一個基本語法,難度極低,但問題爆多的語法。
if在所有的語言的用法都一樣,差別只在有沒有括號跟分號而己:if後面接著一段判斷式,成立的話執行。
if(user.Age > 18)
Page.Redirect('/jazzdrums');
這麼簡單的語法,但常發生:
有看過if長到視窗都長出scroll bar那種嗎?從第一個看到最後一個都考慮搭Uber過去那種。
if(user.Country == Country.Taiwan || user.Country == Country.China || user.Country == Country.USA || user.Country == Country.Japan || user.Country == Country.Singapore || user.Country == Country.Korea)
return true;
上面的例子還算簡單的,有些還會摻雜呼叫方法,可能還會有其他的邏輯一起進來。
但其實這個判斷式沒有錯,但他有兩個問題:
比較好的做法是,把判斷式變成方法,並且適度的重構邏輯判斷式:
if(HasBranch(user.Country)) return true;
...
public bool HasBranch(Country country)
{
return Enum.IsDefined(typeof(Country), country);
}
有看過else多到都蓋過一整頁的那種嗎?從第一個看到最後一個都考慮搭電梯下去那種。
if(user.Level == Level.One)
{
}
else if(user.Level == Level.Two)
{
}
else if(user.Level == Level.Three)
{
}
else if(user.Level == Level.Four)
{
}
else if(user.Level == Level.Five)
{
}
else if(user.Level == Level.Six)
{
}
看起來像switch的if-else-if判斷式雖然確實可以改用switch,但並不能改變一個方法裡包含過多分支的情況。換句話說,這個方法並不是專為某個情況而處理。
有什麼問題嗎?問題可大了。
有比較好的做法嗎?當然有,例如把判斷式分割成不同的方法來呼叫,或者更好的做法:分割成不等分的class,並用factory產生物件,然後統一呼叫一個方法來檢查。
例如,有一個需求,長這個樣子:
The output can be in any format (eg. xml/html/json/csv)
雖然我大可用一個if去判斷需求格式是什麼,但如果透過factory,在Creator裡檢查格式,並回傳輸出格式的介面
public static IOutput CreateOutput(string outputFormat)
{
if(string.IsNullOrEmpty(outputFormat) || outputFormat.Equals("json", StringComparison.InvariantCultureIgnoreCase))
return new JSONOutput();
throw new NotImplementedException("Output format not found.");
}
那原先方法裡的程式碼就變得簡潔多了。
var output = OutputFactory.CreateOutput(argsDictionary["Output"]);
Console.WriteLine(output.Output(result));
(未完待續)