日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁(yè) > 科技  > 軟件

擺脫 if-else 束縛的清潔編碼之旅:這些技術(shù)幫你實(shí)現(xiàn)

來(lái)源: 責(zé)編: 時(shí)間:2024-07-06 07:44:59 961觀看
導(dǎo)讀許多學(xué)生在維護(hù)舊項(xiàng)目時(shí)遇到過(guò)復(fù)雜的業(yè)務(wù)邏輯嵌套在深層的if-else語(yǔ)句中。面對(duì)這樣的亂象,簡(jiǎn)單地增量修改通常只會(huì)增加復(fù)雜性和降低可讀性。那么,有沒(méi)有固定的套路可以整理這些代碼呢?這里分享三種簡(jiǎn)單而常見(jiàn)的重構(gòu)方法

許多學(xué)生在維護(hù)舊項(xiàng)目時(shí)遇到過(guò)復(fù)雜的業(yè)務(wù)邏輯嵌套在深層的if-else語(yǔ)句中。面對(duì)這樣的亂象,簡(jiǎn)單地增量修改通常只會(huì)增加復(fù)雜性和降低可讀性。那么,有沒(méi)有固定的套路可以整理這些代碼呢?這里分享三種簡(jiǎn)單而常見(jiàn)的重構(gòu)方法。FgI28資訊網(wǎng)——每日最新資訊28at.com

什么是意大利面條代碼?

所謂“意大利面條代碼”在處理復(fù)雜業(yè)務(wù)過(guò)程時(shí)很常見(jiàn)。它通常具有以下特點(diǎn):FgI28資訊網(wǎng)——每日最新資訊28at.com

  • 內(nèi)容冗長(zhǎng)
  • 結(jié)構(gòu)混亂
  • 嵌套深

我們知道,主流編程語(yǔ)言都有函數(shù)或方法來(lái)組織代碼。對(duì)于意大利面條代碼,我們可以將其視為滿足這些特點(diǎn)的函數(shù)。根據(jù)語(yǔ)言語(yǔ)義的不同,可以將其分為兩種基本類(lèi)型:FgI28資訊網(wǎng)——每日最新資訊28at.com

if…if 類(lèi)型

這種代碼結(jié)構(gòu)看起來(lái)像這樣:FgI28資訊網(wǎng)——每日最新資訊28at.com

function demo(a, b, c) {  if (f(a, b, c)) {    if (g(a, b, c)) {      // ...    }    // ...    if (h(a, b, c)) {      // ...    }  }  if (j(a, b, c)) {    // ...  }  if (k(a, b, c)) {    // ...  }}

其流程圖如下:FgI28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片FgI28資訊網(wǎng)——每日最新資訊28at.com

通過(guò)自上而下嵌套 if 語(yǔ)句,單個(gè)函數(shù)內(nèi)的控制流不斷增長(zhǎng)。不要以為控制流增長(zhǎng)時(shí),復(fù)雜性只是線性增加。我們知道,函數(shù)處理數(shù)據(jù),每個(gè) if 內(nèi)通常都有數(shù)據(jù)處理邏輯。所以即使沒(méi)有嵌套,如果有 3 個(gè)這樣的 if 段,那么根據(jù)每個(gè) if 是否執(zhí)行,會(huì)有 2 ^ 3 = 8 種可能的數(shù)據(jù)狀態(tài)。如果有 6 段,則會(huì)有 2 ^ 6 = 64 種狀態(tài)。因此,隨著項(xiàng)目規(guī)模的擴(kuò)大,調(diào)試函數(shù)變得指數(shù)級(jí)困難!在數(shù)量級(jí)上,這與《人月神話》中分享的經(jīng)驗(yàn)一致。FgI28資訊網(wǎng)——每日最新資訊28at.com

else if…else if 類(lèi)型

這種代碼控制流也很常見(jiàn),看起來(lái)像這樣:FgI28資訊網(wǎng)——每日最新資訊28at.com

function demo(a, b, c) {  if (f(a, b, c)) {    if (g(a, b, c)) {      // ...    } else if (h(a, b, c)) {      // ...    }    // ...  } else if (j(a, b, c)) {    // ...  } else if (k(a, b, c)) {    // ...  }}

其流程圖如下:FgI28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片FgI28資訊網(wǎng)——每日最新資訊28at.com

else if 最終只會(huì)進(jìn)入其中一個(gè)分支,因此不會(huì)像前面提到的那樣出現(xiàn)組合爆炸。然而,在深層嵌套中,復(fù)雜性依然很高。假設(shè)每層嵌套有 3 個(gè) else if 語(yǔ)句,有 3 層嵌套,則會(huì)有 3 ^ 3 = 27 種可能的出口。如果每個(gè)出口對(duì)應(yīng)一種處理數(shù)據(jù)的方式,那么在一個(gè)函數(shù)內(nèi)封裝這么多邏輯違背了單一職責(zé)原則。而且,這兩種類(lèi)型可以無(wú)縫結(jié)合,進(jìn)一步增加復(fù)雜性和降低可讀性。FgI28資訊網(wǎng)——每日最新資訊28at.com

但為什么在框架和庫(kù)如此先進(jìn)的時(shí)代,我們?nèi)匀唤?jīng)常遇到這樣的代碼?在我看來(lái),可復(fù)用的模塊確實(shí)幫助我們減少了模板代碼;然而,不管業(yè)務(wù)邏輯封裝得多好,開(kāi)發(fā)者仍需要編寫(xiě)它。即使是簡(jiǎn)單的 if-else 語(yǔ)句,也能成倍增加控制流的復(fù)雜性。從這個(gè)角度看,如果沒(méi)有基本的編程技巧,不管多快掌握優(yōu)秀的框架和庫(kù),你可能仍然會(huì)寫(xiě)出混亂的項(xiàng)目。FgI28資訊網(wǎng)——每日最新資訊28at.com

重構(gòu)策略

在上文中,我們討論了兩種面條代碼,并定量展示了它們?nèi)绾纬杀对黾涌刂屏鞯膹?fù)雜性。然而,在現(xiàn)代編程語(yǔ)言中,這種復(fù)雜性實(shí)際上是完全可控的。以下是列舉的幾種編程技巧來(lái)改善面條代碼的場(chǎng)景。FgI28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片FgI28資訊網(wǎng)——每日最新資訊28at.com

基本情況FgI28資訊網(wǎng)——每日最新資訊28at.com

對(duì)于 if…if 類(lèi)型的面條代碼,可以通過(guò)基本函數(shù)拆分來(lái)解決復(fù)雜性增長(zhǎng)的問(wèn)題。下圖中每個(gè)綠色框代表一個(gè)拆分出的新函數(shù):FgI28資訊網(wǎng)——每日最新資訊28at.com

由于現(xiàn)代編程語(yǔ)言中放棄了 goto,無(wú)論控制流多復(fù)雜,函數(shù)體內(nèi)代碼的執(zhí)行順序總是自上而下的。因此,我們完全可以從上到下逐步將單體大函數(shù)拆分為多個(gè)小函數(shù)而不改變控制流邏輯,然后一個(gè)個(gè)調(diào)用它們。這是經(jīng)驗(yàn)豐富的同事常用的技巧,具體代碼實(shí)現(xiàn)這里不再詳細(xì)闡述。FgI28資訊網(wǎng)——每日最新資訊28at.com

需要注意的是,這種方法中所謂的不改變控制流邏輯是指不需要改變業(yè)務(wù)邏輯執(zhí)行的方式,只是將代碼移出去并包裹一層函數(shù)。有些同學(xué)可能認(rèn)為這種方法只是治標(biāo)不治本——它只是將一段長(zhǎng)面條切成幾段短面條,沒(méi)有本質(zhì)區(qū)別。FgI28資訊網(wǎng)——每日最新資訊28at.com

但真的是這樣嗎?通過(guò)這種方法,我們可以將具有 64 種狀態(tài)的大函數(shù)拆分為 6 個(gè)只返回 2 種狀態(tài)的小函數(shù),以及一個(gè)逐一調(diào)用它們的主函數(shù)。這樣,每個(gè)函數(shù)的復(fù)雜性增長(zhǎng)率從指數(shù)級(jí)降低為線性。FgI28資訊網(wǎng)——每日最新資訊28at.com

通過(guò)這種方式,我們解決了 if…if 類(lèi)型的面條代碼;那么else if…else if類(lèi)型的呢?FgI28資訊網(wǎng)——每日最新資訊28at.com

查找表

對(duì)于 “else if…else if” 類(lèi)型的面條代碼,一種最簡(jiǎn)單的重構(gòu)策略是使用所謂的查找表。它以鍵值對(duì)的形式封裝每個(gè) else if 中的邏輯:FgI28資訊網(wǎng)——每日最新資訊28at.com

const rules = {  x: function (a, b, c) { /* ... */ },  y: function (a, b, c) { /* ... */ },  z: function (a, b, c) { /* ... */ }};function demo(a, b, c) {  const action = determineAction(a, b, c);  return rules[action](a, b, c);}

每個(gè) else if 中的邏輯被重寫(xiě)為一個(gè)獨(dú)立的函數(shù),然后我們可以按以下方式拆分過(guò)程:FgI28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片FgI28資訊網(wǎng)——每日最新資訊28at.com

對(duì)于本身支持反射的腳本語(yǔ)言來(lái)說(shuō),這是一個(gè)相對(duì)簡(jiǎn)單的技巧。然而,對(duì)于更復(fù)雜的 else if 條件,這種方法會(huì)將控制流復(fù)雜性重新集中到 determineAction 中,確定該走哪個(gè)分支。有沒(méi)有更好的方法來(lái)處理這個(gè)問(wèn)題呢?FgI28資訊網(wǎng)——每日最新資訊28at.com

責(zé)任鏈模式

在上文中,查找表是通過(guò)鍵值對(duì)實(shí)現(xiàn)的。當(dāng)每個(gè)分支是一個(gè)簡(jiǎn)單判斷時(shí),如 else if (x === ‘foo’),foo 可以作為重構(gòu)集合的鍵。然而,如果每個(gè) else if 分支包含復(fù)雜的條件判斷并且需要特定的執(zhí)行順序,我們可以使用責(zé)任鏈模式來(lái)更好地重構(gòu)這種邏輯。FgI28資訊網(wǎng)——每日最新資訊28at.com

對(duì)于 else if,需要注意每個(gè)分支是自上而下判斷的,最終只會(huì)執(zhí)行其中一個(gè)。這意味著我們可以通過(guò)存儲(chǔ)一個(gè)“判斷規(guī)則”的數(shù)組來(lái)實(shí)現(xiàn)這種行為。如果一個(gè)規(guī)則匹配,則執(zhí)行該規(guī)則對(duì)應(yīng)的分支。我們稱(chēng)這樣的數(shù)組為“責(zé)任鏈”,其模式下的執(zhí)行過(guò)程如圖所示:FgI28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片FgI28資訊網(wǎng)——每日最新資訊28at.com

FgI28資訊網(wǎng)——每日最新資訊28at.com

在代碼實(shí)現(xiàn)中,我們可以通過(guò)責(zé)任鏈數(shù)組定義等價(jià)于else if的規(guī)則。FgI28資訊網(wǎng)——每日最新資訊28at.com

const rules = [  {    match: function (a, b, c) { /* ... */ },    action: function (a, b, c) { /* ... */ }  },  {    match: function (a, b, c) { /* ... */ },    action: function (a, b, c) { /* ... */ }  },  {    match: function (a, b, c) { /* ... */ },    action: function (a, b, c) { /* ... */ }  }  // ...]

rules 中的每項(xiàng)都具有 match 和 action 屬性。此時(shí)我們可以將原來(lái)的 else if 函數(shù)重寫(xiě)為遍歷責(zé)任鏈數(shù)組:FgI28資訊網(wǎng)——每日最新資訊28at.com

function demo (a, b, c) {  for (let i = 0; i < rules.length; i++) {    if (rules[i].match(a, b, c)) {      return rules[i].action(a, b, c)    }  }}

當(dāng)每個(gè)責(zé)任被匹配時(shí),原函數(shù)將直接返回,這也完全符合 else if 的語(yǔ)義。這樣,我們實(shí)現(xiàn)了將復(fù)雜的 else if 邏輯拆分為單獨(dú)的部分。FgI28資訊網(wǎng)——每日最新資訊28at.com

結(jié)尾

面條代碼往往出現(xiàn)在無(wú)腦的“粗暴、快速、猛烈”風(fēng)格的開(kāi)發(fā)中。許多 bug 修復(fù)是通過(guò)粗暴地在這里添加一個(gè) if 并在多處返回語(yǔ)句來(lái)完成的,再加上缺乏注釋?zhuān)@很容易導(dǎo)致代碼可讀性降低和復(fù)雜性增加。FgI28資訊網(wǎng)——每日最新資訊28at.com

然而,解決這個(gè)問(wèn)題其實(shí)并不復(fù)雜。這些示例之所以簡(jiǎn)單,基本上是因?yàn)閺?qiáng)大的高級(jí)編程FgI28資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-99171-0.html擺脫 if-else 束縛的清潔編碼之旅:這些技術(shù)幫你實(shí)現(xiàn)

聲明:本網(wǎng)頁(yè)內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問(wèn)題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: 為什么要限流?及常用的限流算法解析

下一篇: 你合并代碼用 Merge 還是用 Rebase ?

標(biāo)簽:
  • 熱門(mén)焦點(diǎn)
Top 主站蜘蛛池模板: 华容县| 吉林市| 梅州市| 民权县| 屯昌县| 榆林市| 大港区| 专栏| 新和县| 上蔡县| 油尖旺区| 四川省| 包头市| 兴海县| 漳州市| 和田市| 邢台市| 丰县| 铜鼓县| 太康县| 安陆市| 阳东县| 盈江县| 万全县| 临城县| 霸州市| 吴桥县| 永年县| 武功县| 钟祥市| 阿巴嘎旗| 辛集市| 柘城县| 锡林郭勒盟| 阿尔山市| 昌吉市| 沂源县| 岳普湖县| 威远县| 滦南县| 广饶县|