Rider Refactoring 之 Transform Parameters
在實務上常會發現一些 parameter 總是以 primitive type 一起出現,導致 method 內的 parameter 個數過多,也就是 Code Smell 所謂的 Primitive Obsession
,解決方式是將這些 parameter 抽成 class,這在 Refactoring 稱為 Introduce Parameter Object
,而在 Rider 則稱為 Transform Parameters
,且實務上常常搭配 Make Method Non-Static
一起重構。
Version
macOS High Sierra 10.13.4
.NET Core 2.1
Rider 2018.1.3
重構前
StateroomService.cs
第 9 行
1 | public decimal TotalAmount(DateTime startTime, DateTime endTime) |
我們發現 startTime
與 endTime
總是一起出現,這正是典型的 Primitive Obsession
,因此我們想將 startTime
與 endTime
抽成 Period
class。
Primitive Obsession
過度使用程式語言所提供的基本型別,卻忘記使用使用更有意義的 class 型別
Transform Parameters
將 primitive type 的 parameter 抽成 class,也就是 Refactoring 中的 Introduce Parameter Object
。
- 將 cursor 放到要抽的 parameter 上
- 按熱鍵
⌃ + T
,選擇Transform Parameters
- 選擇要抽出的 parameter
- Method receives : 選擇要抽成 Class 或 Tuple
- 輸入 class 名稱
- 按
Next
繼續
- 抽出了
Period
class TotalAmount
的 parameter 也由兩個DateTime
重構成只有一個Period
Rider 預設會將 class 抽在同一個檔案,但實務上建議 1 個檔案只有 1 個 class,因此會繼續重構,將
Period
class 獨立成一個檔案
Move Class to File
將 class 抽成獨立的檔案。
- 將 cursor 放到
Period
上 - 按熱鍵
⌥ + ↩
,選擇Move to 'Period.cs'
- 重構出獨立的
Period.cs
檔案
Extract Method
將一段 code 抽成 method。
days
由period.EndTime
與period.StartTime
計算所得,明明在StateroomService
內,卻一直讀取Period
的資料,這正是典型的Feature Envy
,需進一步抽成 method,然後Move Method
到Period
Feature Envy
不斷的向其他 class 取值,然後在自己的 class 運算
- 選擇要抽取的 code
- 按熱鍵
⌃ + T
,選擇Extract Method
- 選擇
Method
- 按
Next
繼續
- 抽出
Days
method - 預設將
Make static
打勾 - 按
Next
繼續
Make static 的重要性
- 若能抽成
static
,Rider 會自動將Make static
打勾,這表示該 method 已經與此 class 沒有任何瓜葛 (沒使用 field),可隨時Move Method
到其他 class- 若不能抽成
static
,則表示此 method 仍使用該 class 的 field,須先進一步重構,直到能抽成static
method 後,才能Move Method
到其他 class- 若要繼續使用
Make Method Non-Static
重構,則static
method 為其必要條件,否則無法繼續使用Make Method Non-Static
Make Method Non-Static
將 Static
method 重構到 parameter object 的 instance method,也就是 Refactoring 中的 Move Method
。
- 將 cursor 放在
Days()
上 - 按熱鍵
⌃ + T
,選擇Make Method Non-Static
- 選擇要
Move Method
到Period
- 按
Next
繼續
Days()
被搬到Period
- 直接呼叫
period.Days()
Make Method Non-Static
本質上就是Move Method
,只是因為Make Method Non-Static
的名稱,會讓人誤以為只是單純的將一個 method 由static
重構成non-static
而已,但事實上不只單純的重構成non-static
,還會將整個 method 搬到 parameter object 上,所以若Extract Method
所抽出的 parameter,不是要我們要Move Method
的 class,我們還會透過Change Parameter
加以重構 parameter,讓Make Method Non-Static
可以繼續進行
Inline Variable
將不必要的 中介變數
去除。
days
可以再加以 inline
- 將 cursor 放在
days
上 - 按熱鍵
⌃ + T
,選擇Inline Variable
days
變數被 inline 掉了
- 同理,
days
也可再被 inline 掉
days
變數被 inline 掉了
由於
職責
變清楚,因此少掉了很多不必要的 parameter 與 variable,不只 code 變的清爽,可讀性也高,也更容易維護
執行單元測試
- 重新跑單元測試,確認 production code 沒被重構壞掉
Conclusion
Primitive Obsession
是很常見的 Code Smell,由於太堅持使用 primitive type,而喪失發現 object 的機會,導致 OOP 名存實亡,透過 Rider 的Transform Parameters
,我們可以直接將 parameter 將抽成 class,這對 legacy code 重構非常方便Feature Envy
也是很常見的 Code Smell,由於 class A 一直使用 class B,因此需要很多中介的 parameter 與 variable,透過 Rider 的Extract Method
,我們可以直接將 class A 的一段 code 抽成 method,然後透過Make Method Non-Static
般到 class B,這會使得 class 與 class 間的職責
更為清楚,也可將不必要的 parameter 與 variable 重構掉Transform Parameters
與Make Method Non-Static
常常一起執行,因為既然已經使用Transform Parameters
將 parameter 抽成新的 object,根據 OOP 的職責
思維,必然將一些 code 透過Make Method Non-Static
搬到新的 class,如此才能避免Primitive Obsession
與Feature Envy
Sample Code
完整的範例可以在我的 GitHub 上找到