如何沒有 if 語句

2021-08-22 08:54:52 字數 4081 閱讀 4074

大約在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...