偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Go 中常用的四大重構(gòu)技術(shù)

開發(fā) 后端
這是我常應(yīng)用于代碼的技術(shù)。它包括提取一段按意圖分組的代碼,并轉(zhuǎn)移到新方法中。通過提取可以將一個(gè)長(zhǎng)方法或函數(shù)拆分為一些小方法,這些小方法將邏輯組合在一起。通常,小方法或函數(shù)的名稱可以更好地了解該邏輯是什么。

[[433087]]

大家好,我是程序員幽鬼。

Martin Fowler 在他的書中[1]將重構(gòu)定義為*“對(duì)軟件的內(nèi)部結(jié)構(gòu)進(jìn)行的更改,以使其更易于理解,并且在不更改其可觀察到的行為的情況下更低廉地進(jìn)行修改”*。本書包含大量重構(gòu)技術(shù),這些重構(gòu)技術(shù)旨在在某些情況下應(yīng)用,并旨在消除代碼壞味道[2]。

重構(gòu)是一個(gè)非常廣泛的話題,我發(fā)現(xiàn)重構(gòu)在軟件開發(fā)過程中起著重要的作用。它們的相關(guān)性很高,因此它們是TDD[3]生命周期的重要組成部分。

由于它們的重要性,在這篇文章中,我想分享一下軟件開發(fā)人員中使用最多的 4 種重構(gòu)技術(shù)。但是在開始之前,因?yàn)榭梢宰詣?dòng)應(yīng)用重構(gòu)技術(shù)(即某些 IDE 為你提供了幫助,通過應(yīng)用重構(gòu)工具,只需單擊幾下鼠標(biāo)和進(jìn)行選擇,即可使你的生活更輕松),在這里,我將通過使用 Go 語言手動(dòng)重構(gòu)進(jìn)行描述,并嘗試將其作為參考指南。我們的開發(fā)團(tuán)隊(duì)意識(shí)到,在應(yīng)用任何重構(gòu)技術(shù)之前,應(yīng)將可觀察到的功能包含在單元測(cè)試中,并通過所有測(cè)試。

01 提取方法

這是我常應(yīng)用于代碼的技術(shù)。它包括提取一段按意圖分組的代碼,并轉(zhuǎn)移到新方法中。通過提取可以將一個(gè)長(zhǎng)方法或函數(shù)拆分為一些小方法,這些小方法將邏輯組合在一起。通常,小方法或函數(shù)的名稱可以更好地了解該邏輯是什么。

下面的示例顯示了應(yīng)用此重構(gòu)技術(shù)之前和之后的情況。我的主要目標(biāo)是通過將復(fù)雜度分為不同的功能,這樣來抽象其復(fù)雜度。

  1. func StringCalculator(exp string) int { 
  2.     if exp == "" { 
  3.         return 0 
  4.     } 
  5.      
  6.     var sum int 
  7.     for _, number := range strings.Split(exp, ",") { 
  8.         n, err := strconv.Atoi(number) 
  9.         if err != nil { 
  10.             return 0 
  11.         } 
  12.         sum += n 
  13.     } 
  14.     return sum 

重構(gòu)為:

  1. func StringCalculator(exp string) int { 
  2.     if exp == "" { 
  3.         return 0 
  4.     } 
  5.  return sumAllNumberInExpression(exp) 
  6.  
  7. func sumAllNumberInExpression(exp string) int { 
  8.     var sum int 
  9.     for _, number := range strings.Split(exp, ",") { 
  10.         sum += toInt(number) 
  11.     } 
  12.     return sum 
  13.  
  14. func toInt(exp string) int { 
  15.     n, err := strconv.Atoi(exp) 
  16.     if err != nil { 
  17.         return 0 
  18.     } 
  19.     return n 

StringCalculator 函數(shù)更簡(jiǎn)單了,但是當(dāng)添加了兩個(gè)新的函數(shù)時(shí),它會(huì)增加復(fù)雜性。這是一個(gè)我愿意做出慎重決定的犧牲,我將此作為參考而不是規(guī)則,從某種意義上說,了解應(yīng)用重構(gòu)技術(shù)的結(jié)果可以很好地判斷是否應(yīng)用重構(gòu)技術(shù)。

02 移動(dòng)方法

有時(shí),在使用提取方法后,我發(fā)現(xiàn)了另一個(gè)問題:此方法應(yīng)該屬于此結(jié)構(gòu)或包嗎?Move Method 是一種簡(jiǎn)單的技術(shù),包括將方法從一個(gè)結(jié)構(gòu)移動(dòng)到另一個(gè)結(jié)構(gòu)。我發(fā)現(xiàn)一個(gè)技巧,來確定某個(gè)方法是否應(yīng)該屬于該結(jié)構(gòu):弄清楚該方法是否訪問了另一個(gè)結(jié)構(gòu)依賴項(xiàng)的內(nèi)部??聪旅娴睦樱?/p>

  1. type Book struct { 
  2.     ID    int 
  3.     Title string 
  4.  
  5. type Books []Book 
  6.  
  7. type User struct { 
  8.     ID    int 
  9.     Name  string 
  10.     Books Books 
  11.  
  12. func (u User) Info() { 
  13.     fmt.Printf("ID:%d - Name:%s", u.ID, u.Name
  14.     fmt.Printf("Books:%d", len(u.Books)) 
  15.     fmt.Printf("Books titles: %s", u.BooksTitles()) 
  16.  
  17. func (u User) BooksTitles() string { 
  18.     var titles []string 
  19.     for _, book := range u.Books { 
  20.         titles = append(titles, book.Title) 
  21.     } 
  22.     return strings.Join(titles, ","

如你所見,User 的方法BooksTitles 使用了 books(具體是 Title)中的內(nèi)部字段多于User,這表明該方法應(yīng)歸于Books。應(yīng)用這種重構(gòu)技術(shù)將該方法移動(dòng)到Books類型上,然后由用戶的Info方法調(diào)用。

  1. func (b Books) Titles() string { 
  2.     var titles []string 
  3.     for _, book := range b { 
  4.         titles = append(titles, book.Title) 
  5.     } 
  6.     return strings.Join(titles, ","
  7.  
  8. func (u User) Info() { 
  9.     fmt.Printf("ID:%d - Name:%s", u.ID, u.Name
  10.     fmt.Printf("Books:%d", len(u.Books)) 
  11.     fmt.Printf("Books titles: %s", u.Books.Titles()) 

應(yīng)用此方法后,Books類型會(huì)更內(nèi)聚,因?yàn)樗俏ㄒ粨碛锌刂茩?quán)和對(duì)它的字段和內(nèi)部屬性訪問權(quán)的人。同樣,這是在深思熟慮之前進(jìn)行的思考過程,知道應(yīng)用重構(gòu)會(huì)帶來什么結(jié)果。

03 引入?yún)?shù)對(duì)象

你見過多少像下面方法一樣,有很多參數(shù)的:

  1. func (om *OrderManager) Filter(startDate, endDate time.Time, country, state, city, status string) (Orders, error) { 
  2.     ... 

即使我們看不到函數(shù)內(nèi)部的代碼,當(dāng)我們看到大量這樣的參數(shù)時(shí),我們也可以考慮它執(zhí)行的大量操作。

有時(shí),我發(fā)現(xiàn)這些參數(shù)之間高度相關(guān),并在以后定義它們的方法中一起使用。這為重構(gòu)提供了一種使該場(chǎng)景更加面向?qū)ο蟮姆绞竭M(jìn)行處理的方法,并且建議將這些參數(shù)分組為一個(gè)結(jié)構(gòu),替換方法簽名以將該對(duì)象用作參數(shù),并在方法內(nèi)部使用該對(duì)象。

  1. type OrderFilter struct { 
  2.     StartDate time.Time 
  3.     EndDate   time.Time 
  4.     Country   string 
  5.     State     string 
  6.     City      string 
  7.     Status    string 
  8.  
  9. func (om *OrderManager) Filter(of OrderFilter) (Orders, error) { 
  10.     // use of.StartDate, of.EndDate, of.Country, of.State, of.City, of.Status. 

看起來更干凈,并且可以確定這些參數(shù)的身份,但是這將要求我更改調(diào)用此方法的所有引用,并且需要OrderFilter在傳遞給該方法之前創(chuàng)建一個(gè)新類型的對(duì)象作為參數(shù)。同樣,在嘗試進(jìn)行此重構(gòu)之前,我會(huì)盡力思考并考慮后果。當(dāng)你的代碼中的影響程度很低時(shí),我認(rèn)為此技術(shù)非常有效。

04 用符號(hào)常量替換魔數(shù)

該技術(shù)包括用常數(shù)變量替換硬編碼值以賦予其意圖和意義。

  1. func Add(input string) int { 
  2.     if input == "" { 
  3.         return 0 
  4.     } 
  5.  
  6.     if strings.Contains(input, ";") { 
  7.         n1 := toNumber(input[:strings.Index(input, ";")]) 
  8.         n2 := toNumber(input[strings.Index(input, ";")+1:]) 
  9.  
  10.         return n1 + n2 
  11.     } 
  12.  
  13.     return toNumber(input) 
  14.  
  15. func toNumber(input string) int { 
  16.     n, err := strconv.Atoi(input) 
  17.     if err != nil { 
  18.         return 0 
  19.     } 
  20.     return n 

其中 ; 字符是什么意思?如果答案對(duì)我來說不太明確,我可以創(chuàng)建一個(gè)臨時(shí)變量,并使用硬編碼字符設(shè)置該值,以賦予其意義。

  1. func Add(input string) int { 
  2.     if input == "" { 
  3.         return 0 
  4.     } 
  5.  
  6.     numberSeparator := ";" 
  7.     if strings.Contains(input, numberSeparator) { 
  8.         n1 := toNumber(input[:strings.Index(input, numberSeparator)]) 
  9.         n2 := toNumber(input[strings.Index(input, numberSeparator)+1:]) 
  10.  
  11.         return n1 + n2 
  12.     } 
  13.  
  14.     return toNumber(input) 
  15.  
  16.  
  17. func toNumber(input string) int { 
  18.     n, err := strconv.Atoi(input) 
  19.     if err != nil { 
  20.         return 0 
  21.     } 
  22.     return n 

總結(jié)

感謝閱讀,希望對(duì)你有所幫助。重構(gòu)是一個(gè)非常廣泛的話題,本文舉例說明了重構(gòu)中使用最多的四個(gè)。不要將此處提到的內(nèi)容視為理所當(dāng)然,自己嘗試一下。此處描述的重構(gòu)技術(shù)僅用作指導(dǎo)原則,而未作為規(guī)則遵循,意味著它們?cè)谛枰獣r(shí)可以有針對(duì)性地進(jìn)行調(diào)整。最后,我想說我們對(duì)所編寫的所有代碼和所使用的所有工具負(fù)責(zé),我們的經(jīng)驗(yàn)和知識(shí)可以指導(dǎo)我們掌握在每種情況下最適合的技能,我認(rèn)為重構(gòu)技術(shù)確實(shí)值得。

原文鏈接:https://wawand.co/blog/posts/four-most-refactoring-techniques-i-use/

參考資料

[1]書中: https://martinfowler.com/books/refactoring.html

[2]壞味道代碼: https://en.wikipedia.org/wiki/Code_smell

[3]TDD: https://en.wikipedia.org/wiki/Test-driven_development#/media/File:TDD_Global_Lifecycle.png

本文轉(zhuǎn)載自微信公眾號(hào)「幽鬼」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系幽鬼公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: 幽鬼
相關(guān)推薦

2015-04-02 15:50:47

數(shù)據(jù)倉(cāng)庫(kù)數(shù)據(jù)挖掘

2021-09-17 10:50:14

容器 Linux

2010-09-15 13:35:25

SwingHibernateStruts

2020-02-29 09:09:34

物聯(lián)網(wǎng)定位技術(shù)IOT

2020-04-06 20:11:26

區(qū)塊鏈分布式核心技術(shù)

2011-03-21 09:01:49

CSS框架

2015-07-17 09:50:16

Carthage優(yōu)劣比較

2020-06-29 14:52:31

隱私增強(qiáng)技術(shù)PET加密

2017-03-17 19:48:01

人臉識(shí)別

2013-09-02 10:17:05

虛擬化技術(shù)

2015-12-04 13:46:31

技術(shù)人創(chuàng)業(yè)創(chuàng)業(yè)項(xiàng)目

2011-06-22 08:38:35

Java EE

2014-03-27 15:57:45

Android組件Activity

2013-01-06 10:44:43

微軟Windows 8云計(jì)算

2009-12-09 10:15:08

2024-07-15 08:13:12

BERT模型嵌入

2012-07-11 10:41:38

虛擬化

2012-05-29 09:23:23

HTML5移動(dòng)應(yīng)用框架jQTouch

2020-09-22 15:22:04

物聯(lián)網(wǎng)智慧城市技術(shù)

2020-07-28 08:48:49

Python繪圖工具
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)