編程技巧: 重構 if...else if...else...

2021-03-02 掘金開發者社區

本文出自「掘金社區」,歡迎戳「閱讀原文」連結和作者進行技術交流 🎉🎉

前言

新入職的公司,前人留下來一個項目,裡面充斥著大量的 if...else...,則倒是其次,主要連注釋寫的都很少。面對這樣的已經上線的代碼,我並沒有想去重構他因為成本太高,只好鞭策自己不要寫出這種代碼

面對的問題?

有時候,我們可能面對這樣的業務邏輯(教育類公司),如果是回答過題目通過,如果回答過題目沒有通過,如果沒有回答過題目。如果不使用特定的模式,可能會寫出下面這樣的代碼。一坨一坨的 if...else 看著非常不舒服,並且難以維護。

/**

* 初始化函數

* if...else if... 的情況較為簡單

* @return undefined

*/

function init () {

// 是否回答過題目 1-回答過, 通過 2-回答過, 沒有通過 3-沒有回答過

let isAnswer

// 是否是老用戶 1-老用戶 2-新用戶

let isOldUser

if (isAnswer === 1) {

// ...

} else if (isAnswer === 2) {

// ...

} else if (isAnswer === 3) {

// ...

}

if (isOldUser === 1) {

// ...

} else if (isOldUser === 2) {

// ...

}

}

/**

* 初始化函數

* if...else if... 嵌套的情況

* @return undefined

*/

function init () {

if (isAnswer === 1) {

if (isOldUser === 1) {

// ...

} else if (isOldUser === 2) {

// ...

}

} else if (isAnswer === 2) {

if (isOldUser === 1) {

// ...

} else if (isOldUser === 2) {

// ...

}

} else if (isAnswer === 3) {

if (isOldUser === 1) {

// ...

} else if (isOldUser === 2) {

// ...

}

}

}

解決辦法1: 查找表, 職責鏈查找表

雖然可能看著是治標不治本,其實不然,init 函數的複雜度大大的降低了。我們已經把控制流程的複雜邏輯,拆分到 determineAction 函數中

// 可以解決if...else if...簡單的問題

const rules = {

isAnswer1 () {

return code

},

isAnswer2 () {

return code

},

isAnswer3 () {

return code

}

}

function determineAction (type) {

if (isAnswer === 1) {

return 'isAnswer1'

} else if (isAnswer === 2) {

return 'isAnswer2'

} else if (isAnswer === 3) {

return 'isAnswer3'

}

}

function init () {

let key = determineAction(isAnswer)

return rules[key]

}

// 面對if...else if...else 嵌套的複雜情況

const rules = [

{

match (an, old) {

if (an === 1) {

return true

}

},

action (an, old) {

if (old === 1) {

// ...

} else if (old === 2) {

// ...

}

}

},

{

match (an, old) {

if (an === 2) {

return true

}

},

action (an, old) {

if (old === 1) {

// ...

} else if (old === 2) {

// ...

}

}

},

{

match (an, old) {

if (an === 3) {

return true

}

},

action (an, old) {

if (old === 1) {

// ...

} else if (old === 2) {

// ...

}

}

}

]

function init (an, old) {

for (let i = 0; i < rules.length; i++) {

// 如果返回true

if (rules[i].match(an, old)) {

rules[i].action(an, old)

}

}

}

init(isAnswer, isOldUser)

⬆️上面複雜的情況,也可以吧action的判斷抽離出來但是可能要寫出三個抽離的函數,因為an值有三種不同的情況

解決辦法2: 面向切面的編程(AOP)

為 Function 的原型鏈,擴展 after 語法,如果滿足要求直接在函數內運算並返回結果。如果不滿足條件返回 'next' 調用職責鏈的下一個節點。所謂的 Function.prototype.after 就是在本函數執行前執行after添加的函數

// 可以解決if...else if...簡單的問題

Function.prototype.after = function (nextFn) {

let self = this

return function (...rest) {

let code = self(...rest)

if (code === 'next') {

return nextFn(...rest)

}

return code

}

}

// 重構原函數

function isAnswer1 (type) {

if (type === 1) {

return code

}

return 'next'

}

function isAnswer2 () {

if (type === 2) {

return code

}

return 'next'

}

function isAnswer3 () {

if (type === 3) {

return code

}

return 'next'

}

let isAnswerFn = isAnswer1.after(isAnswer2).after(isAnswer3)

isAnswerFn(isAnswer)

// 面對if...else if...else 嵌套的複雜情況

function isAnswer1 (an, old) {

if (an === 1) {

return isOldUserFn1(an, old)

}

return 'next'

}

function isAnswer2 (an, old) {

if (an === 2) {

return isOldUserFn2(an, old)

}

return 'next'

}

function isAnswer3 (an, old) {

if (an === 3) {

return isOldUserFn3(an, old)

}

return 'next'

}

/**

* isAnswer == 1 isOldUser == 1 的情況

*/

function isAnswer1IsOldUser1 (an, old) {

if (old === 1) {

return code

}

return 'next'

}

/**

* isAnswer == 1 isOldUser == 2 的情況

*/

function isAnswer1IsOldUser2 (an, old) {

if (old === 2) {

return code

}

return 'next'

}

/**

* isAnswer == 2 isOldUser == 1 的情況

*/

function isAnswer2IsOldUser1 (an, old) {

if (old === 1) {

return code

}

return 'next'

}

/**

* isAnswer == 2 isOldUser == 2 的情況

*/

function isAnswer2IsOldUser2 (an, old) {

if (old === 2) {

return code

}

return 'next'

}

/**

* isAnswer == 3 isOldUser == 1 的情況

*/

function isAnswer3IsOldUser1 (an, old) {

if (old === 1) {

return code

}

return 'next'

}

/**

* isAnswer == 3 isOldUser == 2 的情況

*/

function isAnswer3IsOldUser2 (an, old) {

if (old === 2) {

return code

}

return 'next'

}

let isAnswerFn = isAnswer1.after(isAnswer2).after(isAnswer3)

// 三條職責鏈

let isOldUserFn1 = isAnswer1IsOldUser1.after(isAnswer1IsOldUser2)

let isOldUserFn2 = isAnswer2IsOldUser1.after(isAnswer2IsOldUser2)

let isOldUserFn3 = isAnswer3IsOldUser1.after(isAnswer3IsOldUser2)

isAnswerFn(isAnswer, isOldUser)

解決辦法3: 函數式編程

利用 ramda 等函數式編程庫解決這種問題, 🔗連結: http://ramda.cn/docs/#cond

import R from 'ramda'

var fn = R.cond([

[R.equals(0), R.always('water freezes at 0°C')],

[R.equals(100), R.always('water boils at 100°C')],

[R.T, temp => 'nothing special happens at ' + temp + '°C']

]);

fn(0); //=> 'water freezes at 0°C'

fn(50); //=> 'nothing special happens at 50°C'

fn(100); //=> 'water boils at 100°C'

相關焦點

  • 不要if else 的編程
    條件控制是編程中與生俱來的一種結構,但對於我來說,除了給我帶來麻煩外,沒有發現任何的用處。一次又一次,我不斷發現,越少的if語句,越少的 switch語句,越少的循環,就會是越好的代碼。通常這其中的原因是程式設計師用程式語言實現了更好的抽象歸納。他們並不是有意識的避免使用控制結構。但他 們確實做到了這些。
  • labview編程技巧---令人無奈的IF ELSE
    LABVIEW作為一種程式語言,相對於常規程式語言,有其獨特的編程風格.程式語言都具有順序,條件轉移和循環三種基本結構.LV的IF ELSE常常令人很無奈.if(condition1) ........else if (condition2) ........
  • AI機器人編程,只是一堆if then else嗎
    談到現在的AI機器人或服務機器人,一些人會這麼認為,哪有什麼人工智慧機器人,哪兒智能了,還不是一堆if then else嗎?持這種看法的人往往是懂編程的人,從編程的邏輯看,的確很多軟體和應用功能無外乎,如果,那麼這樣的邏輯堆積。
  • Python編程思想(13):循環中的else語句
    李寧老師已經在「極客起源」 微信公眾號推出《Python編程思想》電子書,囊括了Python的核心技術,以及Python的主要函數庫的使用方法。
  • Java中我如何去除if...else...語句?
    而且,我們是去除if…else…的語句,這樣的方式雖然好像沒有了if…else…語句,但是本質上並不是最好的方式,只是提供了一種思維方式。讀《重構 改善既有代碼的設計》有一條就是,以多態取代條件表達式。這是才是最本質的解決方式。這裡的去除if…else…語句,不是遇見了if…else…語句就去除。
  • 精準優化if…else,幹掉,過多,爛代碼!
    下面借用《編程珠璣》中的一個稅金計算的例子:if income <= 2200  tax = 0else if income <= 2700  tax = 0.14 * (income - 2200)else if income <= 3200  tax = 70 + 0.15 * (income - 2700)else
  • 編寫精煉的JavaScript代碼:避免多餘的Else, 儘早Return
    {    if () {      result = y    } else {      result = z    }  }  return result // this return is single and lonely}我認為這個編程指導意見不夠詳盡
  • 徹底消滅if-else嵌套
    作為每種程式語言都不可或缺的條件語句,我們在編程時會大量的用到。但if-else一般不建議嵌套超過三層,如果一段代碼存在過多的if-else嵌套,代碼的可讀性就會急速下降,後期維護難度也大大提高。2.2 親歷的重構前陣子重構了服務費收費規則,重構前的if-else嵌套如下。
  • 程式設計師:運用策略模式,重構 if else 冗餘代碼
    一,介紹先上案例if (msgType = "文本") {// dosomething} else if(msgType = "圖片") {// doshomething} else if(msgType = "視頻") {// doshomething} else {// doshomething}隨著代碼的業務邏輯有時候會伴隨著很多的
  • Python高能小技巧:不要在for與while循環後面寫else塊
    導讀:本文會詳細介紹一個小技巧,幫助你用符合Python風格的方式(Pythonic方式)來編寫程序。
  • 求求你們了,別再寫滿屏的 if/ else 了
    如果使用 if-else,說明 if 分支和 else 分支的重視是同等的,但大多數情況並非如此,容易引起誤解和理解困難。是否有好的方法優化?如何重構?方法肯定是有的。重構 if-else 時,心中無時無刻把握一個原則:儘可能地維持正常流程代碼在最外層。
  • CTO:再寫if-else,逮著罰款1000!
    Pexels設計更好的軟體,替換 If-Else 的 5 種方法,從入門到高級示例If-Else 通常是一個糟糕的選擇,它導致設計複雜,代碼可讀性差,並且可能導致重構困難我將向大家展示一些技巧和模式,這些技巧和模式將終結這種可怕的做法。每個示例的難度都會增加。完全不必要的 Else 塊這也許是那些初級開發人員最負罪的之一。
  • 為什麼 if-else 不是好代碼
    拋開劑量談毒性都是耍流氓在使用條件判斷語句的地方,如果代碼量小,需要判斷的場景少的話,那麼沒有比 if-else 更合適的語句,比如下面這樣if(object.getIndex() > 0) {    //do something} else {    //do other things}
  • 別再用Else語句寫代碼了!
    作者丨Joey Colon 譯者丨核子可樂 策劃丨小智 if…else 語句是許多程式設計師在寫代碼時最常用的方式之一。你甚至可以看到許多程式設計師的代碼中嵌套著無數 else 語句。可這樣,真的好嗎?
  • 求求你們了,別再寫滿屏的 if/ else 了!
    = null) 是異常處理,是代碼健壯性判斷,只有 if 裡面才是正常的處理流程,else 分支是出錯處理流程;而第二個例子不管 type 等於 1,2 還是其他情況,都屬於業務的正常流程。對於這兩種情況重構的方法也不一樣。代碼 if-else 代碼太多有什麼缺點?
  • 5種在JavaScript函數中重構If / Else語句的方法
    -2865a4bbfe29在本文中,我將介紹5種通過不必要的if-else語句來整理代碼的方法。有時,你可能處在需要使用if-else邏輯的情況下,尤其是在嘗試構建條件渲染功能時。和警告條款笨拙的if / else語句(尤其是那些嵌套語句)的最後解決方案是no-else-return語句和guard子句。
  • 這滿屏的 if/ else,交接的兄弟快被逼瘋!
    = null) 是異常處理,是代碼健壯性判斷,只有 if 裡面才是正常的處理流程,else 分支是出錯處理流程;而第二個例子不管 type 等於 1,2 還是其他情況,都屬於業務的正常流程。對於這兩種情況重構的方法也不一樣。代碼 if-else 代碼太多有什麼缺點?
  • Python之奇妙的else
    之所以Python — 不僅僅能配合 if 的 else這個特性不夠突出,但是早已經不是什麼秘密了。可能是因為很多程式語言都有else語法,但都不支持這一特性,才使得這個特性如此的不明顯吧,但它卻是Python很有特點的一個特性。喜歡Python讀者君可以加我們Python學習交流 330637182群內有大量的實戰和新手資料視頻千人大群等你加入。
  • 編寫 if 時不帶 else,你的代碼會更好!
    它導致設計複雜,代碼可讀性差,並且可能導致重構困難。但是,If-Else已成為事實上的代碼分支解決方案,這確實是有道理的。這是向所有有抱負的開發人員講授的第一件事。不幸的是,許多開發人員從來沒有前進到更合適的分支策略。
  • 【Python 第23課】 if, elif, else
    為什麼我跳要著講,因為我的想法是先講下最最基本的概念,讓你能用起來,之後你熟悉了,再說些細節。關於if,可以發送數字『7』回顧之前的課程。它除了我們之前講的用法外,還可以配合elif和else使用,使程序的運行順序更靈活。之前說的if,是:「如果」條件滿足,就做xxx,否則就不做。else顧名思義,就是:「否則」就做yyy。