成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

從if else 到 switch case再到抽象

開發 后端
作者認為超過超過兩個else的if ,或者是超過兩個case 的switch的語句比較復雜,為什么這么說?一起來看作者的觀點吧!!

大家覺得在接手遺留代碼時,見到什么東東是最讓人感到不耐煩的?復雜無比的 UML ?我覺得不是。我的答案是,超過兩個 else 的if ,或者是超過兩個case的switch ??墒窃诖a中大量使用 if else switch case 是很正常的事情吧?錯!絕大多數分支超過兩個的 if else 和 switch case 都不應該以硬編碼( hard-coded )的形式出現。

復雜分支從何而來

首先我們要討論的***個問題是,為什么遺留代碼里面往往有那么多復雜分支。這些復雜分支在代碼的***版本中往往是不存在的,假設做設計的人還是有點經驗的話,他應該預見將來可能需要進行擴展的地方,并且預留抽象接口。

但是代碼經過若干個版本的迭代以后,尤其是經過若干次需求細節的調整以后,復雜分支就會出現了。需求的細節調整,往往不會反映到 UML 上,而會直接反映到代碼上。例如說,原本消息分為聊天消息和系統消息兩類,設計的時候自然會把這設計為消息類的兩個子類。但接著有一天需求發生細節調整了,系統消息里面有一部分是重要的,它們的標題要顯示為紅色,這時候程序員往往會做如下修改:

1.在系統消息類上面加一個 important 屬性

2.在相應的 render 方法里面加入一個關于 important 屬性的分支,用于控制標題顏色

程序員為什么會作出這樣的修改?有可能因為他沒意識到應該抽象。因為需求說的是「系統消息里面有一部分是重要的」,對于接受命令式編程語言訓練比較多的程序員來說,他或許首先想到的是標志位──一個標志位就可以區分重要跟不重要。他沒想到這個需求可以用另一種方式來解讀,「系統消息分為重要和不重要兩種類別」。這樣子解讀,他就知道應該對系統消息進行抽象了。
當然也有可能,程序員知道可以抽象,但基于某些原因,他選擇了不這樣做。很常見的一種情況就是有人逼著程序員,以犧牲代碼質量來換取項目進展速度──加入一個屬性和一個分支,遠比抽象重構要簡單得多,如果要做10個這種形式的修改,是做10個分支快還是做10個抽象快?區別顯而易見。

當然, if else 多了,就有聰明人站出來說「不如我們改成 switch case 」吧。在某些情況下,這確實能夠提升代碼可讀性,假設每一個分支都是互斥的話。但是當 switch case 的數量也多起來以后,代碼一樣會變得不可讀。

復雜分支有何壞處

復雜分支有什么壞處?讓我從百度 Hi 網頁版的老代碼里面截取一段出來做個例子。

  1. switch (json.result) {    
  2. case "ok":      
  3. switch (json.command) {        
  4. case "message":        
  5. case "systemmessage":          
  6. if (json.content.from == ""            
  7. && json.content.content == "kicked") {            
  8. /* disconnect */          
  9. else if (json.command == "systemmessage"            
  10. || json.content.type == "sysmsg") {            
  11. /* render system message */          
  12. else {            
  13. /* render chat message */          
  14. }          
  15. break;      
  16. }     
  17.  break;  

這段代碼要看懂不難,因此我提一個簡單問題,以下這個 JSON 命中哪個分支:

  1. "result""ok",   
  2. "command""message",   
  3. "content": { "from""CatChen",   
  4. "content""Hello!" } } 

你很容易就能得到正確答案:這個 JSON 命中 /* render chat message */ (顯示聊天消息)這個分支。那么我想了解一下,你是如何作出這個判斷的?首先,你要看它是否命中 case “ok”: 分支,結果是命中了;然后,你要看它是否命中 case “message”: 分支,結果也是命中了,所以 case “systemmessage”: 就不用看了;接下來,它不命中 if 里面的條件;并且,它也不命中 else if 里面的條件,所以它命中了 else 這個分支。

看出問題來了嗎?為什么你不能看著這個 else 就說出這個 JSON 命中這個分支?因為 else 本身不包含任何條件,它只隱含條件!每一個 else 的條件,都是對它之前的每一個 if 和 else if 進行先非后與運算的結果。也就是說,判斷命中這個 else ,相當于判斷命中這樣一組復雜的條件:

  1. !(json.content.from == "" && json.content.content == "kicked") &&   
  2. !(json.command == "systemmessage" || json.content.type == "sysmsg"

再套上外層的兩個 switch case ,這個分支的條件就是這樣子的:

  1. json.result == "ok" &&   
  2. (json.command == "message" ||   
  3. json.command == "systemmessage") &&   
  4. !(json.content.from == "" &&   
  5. json.content.content == "kicked") &&   
  6. !(json.command == "systemmessage" ||   
  7. json.content.type == "sysmsg"

這里面有重復邏輯,省略后是這樣子的:

  1. json.result == "ok" &&   
  2. json.command == "message" &&   
  3. !(json.content.from == "" &&   
  4. json.content.content == "kicked") &&   
  5. !(json.content.type == "sysmsg"

我們花了多大力氣才從簡簡單單的 else 這四個字母中推導出這樣一長串邏輯運算表達式來?況且,不仔細看還真的看不懂這個表達式說的是什么。

這就是復雜分支難以閱讀和管理的地方。想象你面對一個 switch case 套一個 if else ,總共有3個 case ,每個 case 里面有3個 else ,這就夠你研究的了──每一個分支,條件中都隱含著它所有前置分支以及所有祖先分支的前置分支先非后與的結果。

如何避免復雜分支

首先,復雜邏輯運算是不能避免的。重構得到的結果應該是等價的邏輯,我們能做的只是讓代碼變得更加容易閱讀和管理。因此,我們的重點應該在于如何使得復雜邏輯運算變得易于閱讀和管理。

抽象為類或者工廠

對于習慣于做面向對象設計的人來說,可能這意味著將復雜邏輯運算打散并分布到不同的類里面:

  1. switch (json.result)   
  2. {  
  3. case "ok":  
  4.  var factory = commandFactories.getFactory(json.command);   
  5. var command = factory.buildCommand(json);   
  6. command.execute();  
  7.  break; } 

這看起來不錯,至少分支變短了,代碼變得容易閱讀了。這個 switch case 只管狀態碼分支,對于 “ok” 這個狀態碼具體怎么處理,那是其他類管的事情。 getFactory 里面可能有一組分支,專注于創建這條指令應該選擇哪一個工廠的選擇。同時 buildCommand 可能又有另外一些瑣碎的分支,決定如何構建這條指令。

這樣做的好處是,分支之間的嵌套關系解除了,每一個分支只要在自己的上下文中保持正確就可以了。舉個例子來說, getFactory 現在是一個具名函數,因此這個函數內的分支只要實現 getFactory 這個名字暗示的契約就可以了,無需關注實際調用 getFactory 的上下文。

抽象為模式匹配

另外一種做法,就是把這種復雜邏輯運算轉述為模式匹配:

  1. Network.listen({  "result""ok",   
  2.  "command""message",    
  3. "content": { "from""""content""kicked" } },  
  4.  function(json) { /* disconnect */ });   
  5. Network.listen([{  "result""ok",   
  6.  "command""message",    
  7. "content": { "type""sysmsg" } },   
  8. {  "result""ok",  "command""systemmessage" }], function(json) { /* render system message */ });   
  9. Network.listen({  "result""ok",    
  10. "command""message",   
  11.  "content": { "from$ne""",   
  12. "type$ne""sysmsg" } },   
  13. function(json) { /* render chat message */ }); 

現在這樣子是不是清晰多了?***種情況,是被踢下線,必須匹配指定的 from 和 content 值。第二種情況,是顯示系統消息,由于系統消息在兩個版本的協議中略有不同,所以我們要捕捉兩種不同的 JSON ,匹配任意一個都算是命中。第三種情況,是顯示聊天消息,由于在老版本協議中系統消息和踢下線指令都屬于特殊的聊天消息,為了兼容老版本協議,這兩種情況要從顯示聊天消息中排除出去,所以就使用了 “$ne” (表示 not equal )這樣的后綴進行匹配。

由于 listen 方法是上下文無關的,每一個 listen 都獨立聲明自己匹配什么樣的 JSON ,因此不存在任何隱含邏輯。例如說,要捕捉聊天消息,就必須顯式聲明排除 from == “” 以及 type == “sysmsg” 這兩種情況,這不需要由上下文的 if else 推斷得出。
使用模式匹配,可以大大提高代碼的可讀性和可維護性。

由于我們要捕捉的是 JSON ,所以我們就使用 JSON 來描述每一個分支要捕捉什么,這比一個長長的邏輯運算表達式要清晰多了。同時在這個 JSON 上的每一處修改都是獨立的,修改一個條件并不影響其他條件。

【編輯推薦】

  1. C/C++是程序員必須掌握的語言嗎?
  2. 用C語言的rand()和srand()產生偽隨機數的方法總結
  3. JavaScript 假如default不是switch的***一項
  4. 關于 JavaScript 的 with 語句
  5. 快速排序(Quicksort)的Javascript實現
責任編輯:于鐵 來源: 百度泛用戶體驗
相關推薦

2023-12-20 14:44:33

軟件開發DevOpsNoOps

2016-11-28 16:23:23

戴爾

2020-05-17 13:59:37

物聯網工業物聯網工業4.0

2020-07-16 15:20:13

switch...caif...else語言

2020-08-13 17:18:20

Kubernetes邊緣容器

2019-04-11 15:45:08

ReactMixin前端

2017-09-12 15:26:44

2013-04-08 17:13:14

2021-08-12 18:48:31

響應式編程Bio

2009-08-19 10:41:14

C# switch和c

2023-06-07 08:35:36

2009-07-01 10:11:04

.NETLINQ

2024-12-23 08:00:45

2009-06-08 21:45:46

Javaswitch-case

2023-05-24 09:00:28

DTW邊緣計算APEX

2021-04-20 19:23:07

語法switch-casePython

2019-09-09 16:33:10

華為

2024-09-18 15:19:54

數據倉庫數據飛輪醫療數據

2024-09-28 11:03:23

數據倉庫數據管理

2024-09-26 09:32:48

數據倉庫數據中臺數據飛輪
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 最新国产精品精品视频 | 日本亚洲精品成人欧美一区 | 午夜在线 | 欧美性一区二区三区 | 久久精品国产一区 | 中文字幕在线观看一区二区 | 特黄小视频 | 欧美日韩精品中文字幕 | 桃色五月| 特黄特黄a级毛片免费专区 av网站免费在线观看 | 欧美日韩精品久久久免费观看 | 精品免费国产一区二区三区四区 | 91在线影院| 精品视频一区二区三区四区 | 久干网| 欧美日韩高清在线观看 | 国产精品日韩在线观看一区二区 | 91麻豆蜜桃一区二区三区 | 尹人av| 成人久久 | 久久精品日产第一区二区三区 | 亚洲aⅴ | 东方伊人免费在线观看 | 久色视频在线 | 久久九九免费 | 欧美日韩精品综合 | 99在线资源| 91视频88av | 奇米av| 精品麻豆剧传媒av国产九九九 | 欧美www在线 | 韩国理论电影在线 | 一区二区三区精品在线 | 欧美成人免费电影 | 日一区二区 | 国产91中文 | 欧区一欧区二欧区三免费 | 四虎影院在线免费观看 | 成年人在线播放 | 久久久精品一区 | 精品亚洲一区二区三区 |