天天看點

代碼重構——第一個執行個體

0 引言

随着“網際網路+”的普及,網際網路行業得到了快速蓬勃發展,使得現實生活中人們對網際網路産品的需求逐漸增加,促使網際網路産品功能越來越複雜,項目逐漸失去有效的管理。為滿足項目功能上的需求,提高項目的擴充性和可維護性,必須在保證業務功能不變的情況下進行代碼重構的開發行為。

重構意味着要改變代碼,或者說是重新修改,或者重寫代碼。它并不是簡單的重複工作,這樣的重複工作也是沒有多大意義的。他的意義就在于,在日常的開發中,通過了解業務需求,捋順業務邏輯,把繁雜、備援的代碼盡量簡化,減少子產品之間的耦合。重構的目的是使軟體更容易被了解和修改,并且重構不會改變軟體可觀察的行為,也就是說重構之後代碼的功能和初始代碼的功能完全一樣,任何使用者或者其它未參與重構行為的程式員,并不會意識到項目的更改。

1 實驗内容

1.1 實驗問題

本次實驗是對《重構——改善既有代碼的設計》一書中第一章節執行個體的模拟實作,執行個體是為影片出租店所用的租賃程式。該家影片租賃店具有三種不同類型的影片,包括:新片、兒童片和普通片。顧客到店選擇多種影片租賃,該程式需實作以下功能:根據顧客標明的影片及顧客待租賃的天數,直接列印顧客賬單,賬單中包括:顧客租賃的每一個影片的費用、所有影片的總費用及目前使用者的積分。

1.2 實驗分析

根據該執行個體,設計出以下三個類:Movie、Customer和Rental。其中,Movie類是一個純資料類,該類中包含:有影片類型的編号将三種不同的影片區分開來。再根據不同的影片類型調用Rental類,并記錄下顧客租賃的租期。原始程式中,将計算價格和積分及輸出列印價格積分全部在Customer類中實作。該類中包括顧客的姓名,顧客租賃影片的類型及租期,計算顧客租賃影片的價格及累計的積分。

最後,我們可以加入一個Main類,聲明一個主函數,用來管理其餘三個類。該程式則可以實作,店家輸入顧客租賃的影片名、影片類型、租賃天數及顧客的姓名,程式輸出列印目前顧客需繳納的費用及累計積分。該程式UML類圖及三個類函數之間的互動如下:

代碼重構——第一個執行個體

圖1 初始代碼類圖

代碼重構——第一個執行個體

圖2 初始代碼中statement()函數互動

2 重構過程

2.1 重構背景

如果将該執行個體隻是作為某一項目中的一小部分待實作的功能,我們再次觀察這三個類,會發現存在“超類”的情況。在原始代碼Customer類中實作了計算價格和輸出列印兩個功能,這不符合“一個類隻能有一個引起該類變化的原因”的原則。

為友善商家使用,商家提出需要增加網頁顯示的功能,在html表單中顯示顧客的消費情況。那麼我們需要再次增加一個htmlprintf()函數,該函數需實作的功能與原statement()中的類似,我們很容易想到,直接複制statement()函數中的功能。但是,如果當影片的計費規則和分類規則不斷地發生變化時,我們需要在兩個函數中不停地更改規則,這就使得程式容易出現bug。

總之,該程式的擴充性和可維護性都不夠好,為程式後期增加功能的友善,也為了其他程式員友善讀懂該程式,我們需要對程式進行代碼重構。

2.2 具體過程

2.2.1 關于影片價格計算

在Customer類中的statement()函數,實作的功能有:計算租賃影片的費用、顧客積分以及輸出列印三個功能,很明顯這不符合這相當于一個“超函數”。是以,我們增加一個計算租賃影片的費用的函數getTotalCharge(),在statement()函數中調用該函數。而計算價格函數,隻涉及到影片租賃價格和租賃天數兩個變量。我們在Rental類中,實作getCharge();而在Movie類中,我們利用Rental類傳遞的參數租賃天數,計算影片的價格。

由于不同類型的影片的租賃價格有所不同,最終,我們增加Price類、CHILDRENS_Price類、NEW_RELEASE_Price類和REGULAR_Price類。在Price類中加入計算價格的抽象函數abstract double getCharge(int daysRented),其中CHILDRENS_Price類、NEW_RELEASE_Price類和REGULAR_Price類繼承Price類,并重寫父類中的getCharge(int daysRented)函數,分别實作各自類型影片的租賃價格計算。

2.2.2 關于顧客積分計算

顧客積分的計算方式同不同類型影片租賃價格計算方式原理相同,我們将初始代碼Customer類中的statement()函數中的積分功能提取出來,采用價格計算同樣的方式去重構。最後,我們在Price類中增加int getFrequentRenterPoints(intdaysRented)函數,在其餘三個子類中重寫計算積分函數,實作不同類型影片計算顧客積分的功能。

2.2.3 整體完善

在重構的過程中,産生了一些不再使用的變量和接口,一些臨時變量往往容易引發問題,它們會導緻大量參數被傳來傳去,而其實完全沒有這種必要。是以我們将一些不必要的變量和接口進行去除或者修改。

2.3 重構方法

2.3.1 Extract Method

當看到一個方法過長或者方法很難讓人了解其意圖的時候,這時候就可以用提取方法這種重構手法。在該執行個體中的statement()函數中,存在一個明顯的switch邏輯結構,我們可以采用提取方法将其提取到獨立函數中。

2.3.2 MoveMethod

明确函數所在類的位置是很重要的。這樣可以避免類與其它類有太多耦合。也會讓程式中類的内聚性變得更加牢固,讓整個系統變得更加整潔。簡單來說,如果在程式中,某個類的函數在使用的過程中,更多的是在和别的類進行互動,調用後者或者被後者調用,那麼就要注意了,我們要去判斷這個類是否真正适合它原來所在的類。

這套手法就是在該函數最常引用的新類中建立一個有着類似行為的新函數,讓舊函數變成一個單純的委托函數或者完全删掉。在該執行個體中,我們将statement()函數中計算價格的功能單獨提取後,發現新的函數放錯了位置,它與Customer類并無多大聯系,我們将其搬移到Rental類中,并不會改變整個程式的功能。是以我們采用了搬移方法将計算租賃價格的函數搬移至Rental類中。

2.3.3 Strategy Pattern

政策模式是指對一系列的算法定義,并将每一個算法封裝起來,而且使它們還可以互相替換。政策模式讓算法獨立于使用它的客戶而獨立變化。當多個類隻差別在表現行為不同,可以用該模式,在運作時動态選擇具體要執行的行為。需要在不同情況下使用不同的政策,或者政策還可能在未來用其它方式實作。在該執行個體中,将不同類型影片租賃價格的計算采用政策模式,以實作代碼的重構。

3 重構效果展示與分析

3.1 重構前後程式結果

我設定了幾組不同的測試用例,對重構前後的代碼進行測試,得到了相同的結果,說明代碼重構成功。

代碼重構——第一個執行個體

圖3 程式運作結果展示

3.2 重構後程式的分析

運用政策模式後的主要類圖如下

代碼重構——第一個執行個體

圖4 政策模式類圖

參考資料

[1](美)福勒.重構:改善既有代碼的設計[M].人民郵電出版社, 2010-11-1:1-52

[2] https://www.aliyun.com/jiaocheng/531223.html

[3]https://blog.csdn.net/Nuan_Feng/article/details/70555952

[4]https://blog.csdn.net/u012401711/article/details/52463347

 源碼https://download.csdn.net/download/qq_35616167/10468620

版權聲明:本文為部落客原創文章,轉載請注明出處。https://blog.csdn.net/qq_35616167/article/details/80631430

繼續閱讀