重构-改善既有代码的设计:简化条件表达式(七)
你有一個(gè)復(fù)雜的條件語(yǔ)句。從if、then、else三個(gè)段落中分別提煉出獨(dú)立函數(shù)。
程序之中,復(fù)雜的條件邏輯是最常導(dǎo)致復(fù)雜度上升的地點(diǎn)之一。你必須編寫(xiě)代碼來(lái)檢查不同的條件分支、根據(jù)不同的分支做不同的事,然后,你很快就會(huì)得到一個(gè)相當(dāng)長(zhǎng)的函數(shù)。大型函數(shù)自身就會(huì)使代碼的可讀性下降,而條件邏輯則會(huì)使代碼更難閱讀。在帶有復(fù)雜條件邏輯的函數(shù)中,代碼(包括檢查條件分支的代碼和真正實(shí)現(xiàn)功能的代碼)會(huì)告訴你發(fā)生的事,當(dāng)常常讓你弄不清為什么會(huì)發(fā)生這樣的事,這就說(shuō)明代碼的可讀性的確大大降低了。
???????和任何大塊頭代碼一樣,你可以將它分解為多個(gè)獨(dú)立函數(shù),根據(jù)每個(gè)小塊代碼的用途,為分解的新函數(shù)命名,并將原函數(shù)中對(duì)應(yīng)的代碼改為調(diào)用新建函數(shù),從而更清楚的表達(dá)自己的意圖。對(duì)于條件邏輯,將每個(gè)分支條件分解為新函數(shù)還可以給你帶來(lái)更多好處:可以突出條件邏輯,更清楚地表明每個(gè)分支的作用,并且突出每個(gè)分支的原因。
2.Consolidate Conditional Expression 合并條件表達(dá)式
你有一系列條件測(cè)試,都得到相同結(jié)果。將這些測(cè)試合并為一個(gè)條件表達(dá)式,并將這個(gè)條件表達(dá)式提煉為一個(gè)獨(dú)立函數(shù)。
有時(shí)你會(huì)發(fā)現(xiàn)這樣一串條件檢查:檢查條件各不相同,最終行為卻一致。如果發(fā)現(xiàn)這種情況,就應(yīng)該使用“邏輯或”和“邏輯與”將它們合并為一個(gè)條件表達(dá)式。
???????之所以要合并條件表達(dá)式,有2個(gè)重要原因。首先,合并后的條件代碼會(huì)告訴你“實(shí)際上只有一次條件檢查,只不過(guò)有多個(gè)并列條件需要檢查而已”,從而使這一次檢查的用意更清晰。當(dāng)然,合并前和合并后的代碼有著相同的結(jié)果,但原先代碼傳達(dá)出的信息卻是“這里有一些各自獨(dú)立的條件測(cè)試,它們只是恰好同時(shí)發(fā)生”。其次,這項(xiàng)重構(gòu)往往可以為你使用Extract Method(提煉方法)做好準(zhǔn)備。將檢查條件提煉成一個(gè)獨(dú)立函數(shù)對(duì)于厘清代碼意義非常有用,因?yàn)樗衙枋觥白鍪裁础暗恼Z(yǔ)句換成了“為什么這樣做”。
???????條件語(yǔ)句的合并理由也同時(shí)指出了不要合并的理由:如果你認(rèn)為這些條件檢查的確彼此獨(dú)立,的確不應(yīng)該被視為同一次檢查,那么就不要使用本項(xiàng)重構(gòu)。因?yàn)樵谶@種情況下,你的代碼已經(jīng)清晰表達(dá)出自己的意義。
3.Consolodate Duplicate Conditional Fragments 合并重復(fù)的條件片段
在條件表達(dá)式的每個(gè)分支上有著相同的一段代碼。將這段重復(fù)代碼移到條件表達(dá)式之外。
一組條件表達(dá)式的所有分支都執(zhí)行了相同的某段代碼。你應(yīng)該將這段代碼搬移到表達(dá)式外面。這樣,代碼才能更清楚地表明哪些東西隨條件變化而變化、哪些東西保持不變。
4.Remove Control Flag 移除控制標(biāo)記
在一系列布爾表達(dá)式中,某個(gè)變量帶有“控制標(biāo)記’的作用。
以break或return語(yǔ)句取代控制標(biāo)記。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
在一系列條件表達(dá)式中,常常會(huì)看到用以判斷何時(shí)停止條件檢查的控制標(biāo)記。這樣的標(biāo)記帶來(lái)的麻煩超過(guò)了它所帶來(lái)的便利。人們之所以會(huì)使用這樣的控制標(biāo)記,因?yàn)榻Y(jié)構(gòu)化編程原則告訴他們:每個(gè)子程序只能有一個(gè)入口和出口。“單一出口“原則會(huì)讓你在代碼中加入讓人討厭的控制標(biāo)記,大大降低條件表達(dá)式的可讀性。這就是編程語(yǔ)言提供break和continue語(yǔ)句的原因:用它們跳出復(fù)雜的條件語(yǔ)句。去掉控制標(biāo)記所產(chǎn)生的效果往往讓你大吃一驚:條件語(yǔ)句真正的用途會(huì)清晰得多。
5.Replace Nested Conditional with Guard Clauses 以衛(wèi)語(yǔ)句取代嵌套條件表達(dá)式
函數(shù)中的條件邏輯使人難以看清正常的執(zhí)行途徑。使用衛(wèi)語(yǔ)句表現(xiàn)所有特殊情況。
條件表達(dá)式通常有2種表現(xiàn)形式。第一:所有分支都屬于正常行為。第二:條件表達(dá)式提供的答案中只有一種是正常行為,其他都是不常見(jiàn)的情況。
???????這2類(lèi)條件表達(dá)式有不同的用途。如果2條分支都是正常行為,就應(yīng)該使用形如if…..else…..的條件表達(dá)式;如果某個(gè)條件極其罕見(jiàn),就應(yīng)該單獨(dú)檢查該條件,并在該條件為真時(shí)立刻從函數(shù)中返回。這樣的單獨(dú)檢查常常被稱(chēng)為“衛(wèi)語(yǔ)句”。
?????? Replace Nested Conditional with Guard Clauses?(以衛(wèi)語(yǔ)句取代嵌套條件表達(dá)式)的精髓是:給某個(gè)分支以特別的重視。它告訴閱讀者:這種情況很罕見(jiàn),如果它真的發(fā)生了,請(qǐng)做一些必要的整理工作,然后退出。
???????“每個(gè)函數(shù)只能有一個(gè)入口和一個(gè)出口”的觀念,根深蒂固于某些程序員的腦海里。現(xiàn)今的編程語(yǔ)言都會(huì)強(qiáng)制保證每個(gè)函數(shù)只有一個(gè)入口,至于“單一出口”規(guī)則,其實(shí)不是那么有用。保持代碼清晰才是最關(guān)鍵的:如果單一出口能使這個(gè)函數(shù)更清晰易讀,那么就使用單一出口;否則就不必這么做。
(衛(wèi)語(yǔ)句就是把復(fù)雜的條件表達(dá)式拆分成多個(gè)條件表達(dá)式,比如一個(gè)很復(fù)雜的表達(dá)式,嵌套了好幾層的if - then-else語(yǔ)句,轉(zhuǎn)換為多個(gè)if語(yǔ)句,實(shí)現(xiàn)它的邏輯,這多條的if語(yǔ)句就是衛(wèi)語(yǔ)句.)
6.Replace Conditional with Polymorphism 以多態(tài)取代條件表達(dá)式
你手上一個(gè)條件表達(dá)式,它根據(jù)對(duì)象類(lèi)型的不同而選擇不同的行為。將這個(gè)條件表達(dá)式的每個(gè)分支放進(jìn)一個(gè)子類(lèi)的覆寫(xiě)函數(shù)中,然后將原始函數(shù)聲明為抽象函數(shù)。
? ? ? 多態(tài)的最根本的好處是:如果你需要根據(jù)對(duì)象的不同類(lèi)型而采取不同的行為,多態(tài)使你不必編寫(xiě)某些的條件表達(dá)式。
???????正因?yàn)橛辛硕鄳B(tài),所以你會(huì)發(fā)現(xiàn):“類(lèi)型嗎的switch語(yǔ)句”以及 ”基于類(lèi)型名稱(chēng)的if-then-else語(yǔ)句“在面向?qū)ο蟪绦蛑泻苌俪霈F(xiàn)。
???????多態(tài)能夠給你帶來(lái)很多好處。如果同一組條件表達(dá)式在程序的許多地點(diǎn)出現(xiàn),那么使用多態(tài)的收益是最大的。使用條件表達(dá)式時(shí),如果你想添加一種新類(lèi)型,就必須查找并更新所有條件表達(dá)式。但如果使用多態(tài),只需建立一個(gè)新的子類(lèi),并在其中提供適當(dāng)?shù)暮瘮?shù)就行了。類(lèi)的用戶(hù)不需要了解這個(gè)子類(lèi),這就大大降低了系統(tǒng)各部分之間的依賴(lài),使系統(tǒng)升級(jí)更加容易。
7.?Introduce Null Object 引入Null對(duì)象
你需要再三檢查某對(duì)象是否為null。將null值替換為null對(duì)象。
多態(tài)的最根本好處在于:你不必再向?qū)ο笤?xún)問(wèn)“你是什么類(lèi)型”而后根據(jù)得到的答案調(diào)用對(duì)象的某個(gè)行為-你只管調(diào)用該行為就是了,其他的一切多態(tài)機(jī)制會(huì)為你安排妥當(dāng)。當(dāng)某個(gè)字段內(nèi)容是null時(shí),多態(tài)可扮演另一個(gè)較不直觀的用途。
8.?Introduce Assertion 引入斷言
某一段代碼需要對(duì)程序狀態(tài)做出某種假設(shè)。以斷言明確表現(xiàn)這種假設(shè)。
常常會(huì)有這樣一段代碼:只有當(dāng)某個(gè)條件為真時(shí),該段代碼才能正常運(yùn)行。
???????這樣的假設(shè)通常并沒(méi)有在代碼中明確表現(xiàn)出來(lái),你必須閱讀整個(gè)算法才能看出。有時(shí)程序員會(huì)以注釋寫(xiě)出這樣的假設(shè)。可以使用斷言明確標(biāo)明這些假設(shè)。
???????斷言是一個(gè)條件表達(dá)式,應(yīng)該總是為真。如果它失敗,不是程序員犯了錯(cuò)誤。因此斷言的失敗應(yīng)該導(dǎo)致一個(gè)非受控異常。斷言絕對(duì)不能被系統(tǒng)的其他部分使用。實(shí)際上,程序最后的成品往往將斷言刪除。因此,標(biāo)記“某個(gè)東西是個(gè)斷言”是很重要的。
???????斷言可以作為交流與調(diào)試的輔助。在交流的角度上,斷言可以幫助程序閱讀者了解代碼所做的假設(shè);在調(diào)試的角度上,斷言可以在距離bug最近的地方抓住它們。
總結(jié)
以上是生活随笔為你收集整理的重构-改善既有代码的设计:简化条件表达式(七)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 重构与模式:改善代码三部曲中的第三部
- 下一篇: 重构-改善既有代码的设计:简化函数调用