大約在10年前,我遇到了反 if 運動(anti-if campaign,乙個**),覺得這是乙個荒謬的概念。如果不使用 if 語句,你究竟如何才能做出乙個有用的程式?荒謬。
但是它會引發你的思考。你還記得你上週不得不去理解的深度巢狀語句嗎?這是不是有點糟糕?如果有一種方法可以讓它變得簡單就好了。
if 語句的問題
if 語句的第乙個問題是它常常使得**可以很容易的以錯誤的方式修改。讓我們從乙個新的 if 語句的誕生開始:
public
void
theproblem(boolean somecondition) else
}
上面的**不算多差,但是已經給我們丟擲了一些問題。當我閱讀這段**時,我必須要檢查codeblocka和codeblockb是如何修改相同的sharedstate的。現在可能很容易閱讀,但是隨著codeblocks的增長與耦合度的增加,閱讀會變得越來越困難。
你經常會看到上面的codeblocks被濫用,裡面有巢狀的 if 語句和返回語句,這樣會導致通過**很難看出業務邏輯是什麼。
if 語句的第二個問題在於當它們重複的時候,意味著缺少域的概念。通過將各種東西組合在一起來增加耦合度是很容易的,但是增加了**的閱讀和重構難度。
if 語句的第三個問題是你必須在大腦中模擬執行,把自己當成乙個迷你電腦,這會消耗你的精神能量,你本該把精力用在解決問題上面,現在卻用來理解理清那些錯綜複雜的**是如何編織在一起的。
我想告訴你我們可以使用的模式,但是首先有乙個警告。
凡事要適度
if 語句通常會使你的**更加複雜,但我們不想徹底禁止他們,我已經看到了一些非常令人髮指的**,目的是刪除所有if語句的痕跡,我們希望避免陷入這樣的陷阱。
對於我們下面將要學習的每個模式,我將為你提供使用它的容差。
在其他地方沒有重複的單個 if 語句可能沒有問題,當你使用重複的 if 語句時,你就開始犯錯誤了。
在**段的外部,當你與危險的外部世界對話時,你希望驗證傳入的響應,因此也改變了你的行為;但是在我們自己**的內部,在那些值得信賴的守門人背後,我認為我們有很好的機會來使用簡單、豐富並且有效的替代辦法。(好晦澀啊,跳過這段吧)
模式1:布林引數
背景:您有乙個方法,它接受乙個改變其行為的布林值
public
void
example()
public
class
fileutils else
}}
問題:當你看到這種**的時候,可以發現它實際上是兩個方法**在一起了,布林值代表了在**中更新概念的一次機會。
容差:通常當你看到此上下文時,你可以在編譯時確定**將如何執行。如果是這種情況,那麼常用的就是本模式。
解決方案:將原方法拆分為兩個新的方法,瞧!if 語句不見了。
public
void
example()
public
class
fileutils
public
static
void
createtemporaryfile(string name, string contents)
}
模式2:使用多型性
背景:你正在根據型別進行切換
public
class
bird
private
boolean isnailed;
private species type;
public
double
getspeed()
}private
double
getloadfactor()
private
double
getbasespeed()
}
問題:當我們新增新的型別時,必須記得更新switch語句。此外,由於增加了新的型別,所以鳥這個類的內聚性也受到了影響。
public
abstract
class
bird
protected
double
getbasespeed()
}public
class
europeanbird
extends
bird
}public
class
africanbird
extends
bird
}public
class
norwegianbird
extends
bird
}
模式3:空物件/空指標傳遞
背景:如果別人想要理解你所寫**的主要目的,那可以檢查傳入空指標時的情況。
public
void
example()
private
intsumof(listnumbers)
return numbers.stream().maptoint(i -> i).sum();
}
問題:你的方法必須檢查是否傳遞了空指標。
容差:你有必要在**段外面進行防禦,但是在**段中處於守勢可能意味著你的**很爛,不要寫爛**!
解決方案:使用空物件或者是可選擇型別來代替空指標,空集合是乙個不錯的選擇。
public
void
example()
private
intsumof(listnumbers)
模式4:內聯宣告成表示式
背景:你有乙個if樹,用來計算乙個布林表示式。
public
boolean
horrible(boolean foo, boolean bar, boolean baz)
}if (baz) else
}
問題:這段**迫使你用大腦來模擬計算機的執行過程。
解決方案:將 if 語句簡化為乙個表示式。
public
boolean
horrible(boolean foo, boolean bar, boolean baz)
模式5:給出乙個應對策略
背景:你準備呼叫其他**,但是你不確定這樣是否能成功。
public
class
repository
}public
class
finder else
}}
問題: 每次處理相同的物件或資料結構時,這些語句都是多重的,它們和空指標有隱藏的耦合,其他物件可能會返回沒有意義的魔法值。
容差: 最好把 if 語句放在乙個地方,這樣我們可以減小空物件和魔法值的耦合。
解決方案: 下面給出一種應對策略的**。ruby 的 hash#fetch 是乙個很好的例子,這種模式甚至可以進一步刪除異常。
private
class
repository
return defaultvalue;
}}public
class
finder
}
總結
希望你能用到一些我們前文所介紹的模式,我發現它們在重構**的時候很有用。
if 語句不是任何時候都不適用的,但是現代語言有很多豐富的特性,我們應該加以利用。
沒有報錯也沒有提示如何如何列印日誌
在mybatis的jar包裡有乙個log4j的jar包,放入專案的lib裡 然後加上log4j的配置檔案放入資源資料夾 開啟log4j.rootlogger debug log4j.rootlogger debug,console關閉log4j.rootlogger error或者log4j.roo...
Switch語句沒有case的例子
在學習c語言的時候,這方面就沒有弄得很清楚。下面舉例說明 int a 2 int b 3 switch a system.out.println b b 這段 的特點是每一句都沒有break,所以每一句都不會跳出。首先查詢2,沒有對應的case,直接執行default b 4。由於沒有break,直...
switch語句沒有break造成錯誤
switch語句中,如果有加break則執行到時會跳出switch語句,執行switch語句之後的語句 如果沒加break則會去執行switch中後續的語句,比如執行到後續別的case中。case只是個入口,如果沒有break,會從入口處將後面所有的case全部執行一次。例如 include usi...