
答應我,别再寫上千行的類了好嗎?
最近在對已有項目進行擴充的時候,發現要改動的一個類它長766行,開放了近40個public接口,我流着淚把它給改完了。為了防止這樣的慘劇再次發生在我的身上,我覺得有必要寫一篇部落格來讓廣大程式猿同胞知道代碼重構的重要性。
如果你身邊有一個類寫上千行的猿,一定要把此文轉給ta
為什麼類不能過長?
類過長——讀不通,擴充不通
- 讀不通——直接用滾輪滾都得好幾秒,就算是原作者,時間長了恐怕也難以理清整個類,更不用說是其他的讀者
- 擴充不通——一個類有過多的接口,會讓擴充這個類變得異常困難,一動千行
類過長——可能有備援代碼
此時CV工程師打了個冷戰
備援代碼,就是重複代碼,通常出自使用Ctrl+C,Ctrl+V來生産代碼的CV工程師之手,備援代碼的危害非常大:
1、備援代碼使方法、類過長,不簡潔
2、備援代碼會造成發散式修改(備援代碼需要變動時,每一處Ctrl+V都需要修改)
類過長——多半是職責過多
一個類開放幾十個接口,絕對存在職責過多的問題,就像圖中的Tom貓一樣手忙腳亂,一個類的職責過多也有巨大問題:
1、違反設計原則——單一職責原則(單一職責原則要求一個類隻實作一個職責,比如一隻Tom隻做掃地、擦桌、拖地中的一件事,而其他事的實作可以轉移給史派克狗或肥胖女傭),違反了這個原則會導緻發散式變化、發散式修改、類過長等代碼問題,還會讓你的類難以擴充,甚至會讓其他程式猿認為你不專業
2、發散式變化(指引發此類修改的地方很多),如果一個類的職責很多,那它的扇入(調用者)一定很多,每個調用者的修改都有可能讓你這個類不得不随之修改,也就是發散式變化,就是說不管哪兒出了問題,你這個類都得遭殃
3、發散式修改(指此類修改引發修改的地方很多),相同的,如果一個類職責很多,那支撐它實作的下級,即扇出(被調用方)一定很多,如果此類邏輯發生變動,所有下級被調用者可能都得随之修改,也就是發散式修改,就是說你這個類出了問題,不管哪兒都會遭殃
4、難以擴充:如果你的一個類接口非常多,那它的子類怎麼辦?它的包裝類怎麼辦?難道全部都要實作這麼多接口,全部都要承擔同樣多的職責嗎?擴充起來真的非常麻煩
5、觸發機關:【測試之怒】【運維之怒】
我已經寫了幾千行了,怎麼辦?
重構——抽取備援代碼
抽取備援代碼就是将重複代碼抽取成一個獨立的方法,之後再使用這段代碼時就不再需要Ctrl + C,Ctrl + V,而是直接調用對應的方法即可,關注微信公衆号:Java技術棧,回複:idea,擷取一份 IDEA 完整版快捷鍵大全。
這樣做也可以縮短原方法,使原方法更加簡潔易懂
更值得一提的是如果這段代碼需要修改,也隻需修改一處,而不是發散式地到處修改,優秀 Java 程式員寫代碼的風格,這篇推薦看下。
真是一箭三雕
使用IDEA進行備援代碼的抽取
1、找到重複代碼
2、進行方法抽取 右鍵->選擇重構->抽取->方法 (或者直接使用快捷鍵Ctrl + Alt + m)
自動檢測出個别重複代碼的細微差别,有些代碼可能隻改動一兩個變量,IDEA會自動檢測出來,并在抽取方法時提醒我們,選擇左側Accept Signature Change(接受簽名變動)可以使抽取的方法自動替換更多的重複點
可以選擇替換掉所有的重複代碼(竟然有18處)
3、重構——更改方法簽名
如果你對抽取出的方法的名字、參數、傳回值或是修飾符不滿意,不要使用Ctrl + R 修改,IDEA提供了重構方法——更改簽名(快捷鍵Ctrl + F6),關注微信公衆号:Java技術棧,回複:idea,擷取一份 IDEA 完整版快捷鍵大全。
注意:方法的名字指的是方法做了什麼,而非怎麼去做,最好是 動詞+名詞格式
比如:Tom.掃地() √
Tom.掃地With掃把() ×
Tom.用掃把掃地() ×
重構——轉移成員變量+函數(轉移職責)
将不應該由自己管理的成員變量和函數轉移出去
那就要考慮兩個問題:該轉移誰?轉移給誰?
來看一個圖
1、圖中成員【偏A】被類【A】調用兩次,而隻被它所在的類【過長類】調用1次,因而應該轉移給【A】去管理
2、由于函數【偏A】與成員【偏A】的親密度較高(隻調用了【偏A】),因而應與【偏A】共進退,同去留,轉移給【A】
3、成員【偏B】和函數【偏B】也是相同道理
4、職責1(函數【1】和成員【偏職責1】)和職責2(函數【2】和成員【偏職責2】)由于找不到可轉移的合适的類,是以應抽取出一個新的類
注意,先決定移動哪個成員變量,然後再決定移動哪個函數
使用IDEA轉移成員變量和函數
1、移動成員變量,滑鼠選擇成員變量->右鍵->Refactor->Move,然後選擇轉移至哪個類
2、移動函數(與移動成員變量步驟相同)
重構——抽取類
當你發現要轉移的成員變量和函數找不到合适的類時(轉移職責卻找不到下家),要想起來,這裡是程式世界,而我們程式猿就是類和對象的造物主,是時候建立一個新的類,讓它來替我們分擔職責(成員變量和函數)了。
推薦看下:狗屎一樣的代碼。
使用IDEA抽取類
1)重構
選中要搬的成員變量和函數,右鍵->Refactor->Extract->Delegate(抽取一個委托者,委托他來管理這部分變量和函數,如果隻有變量或隻有函數,可以抽出參數對象Paramater Object或方法對象Method Object)
不推薦抽取參數對象,因為一般參數對象是給參數多的方法用的(用參數對象取代一長溜的參數),而且如果成員變量抽取了也不會影響任何函數的話,那就是無用對象了,不如直接把他們删除掉
2)為新類起個名,選個包吧
3)注意,抽取的函數和成員一定要符合一個原則,那就是被抽取函數使用被抽取成員的次數一定高于剩餘函數的次數,不然違反親密性原則(成員應歸于調用它最多的類,沒有理由你用的比我多還讓我來管理)
4)一些小問題
由于抽取的函數直接使用了未抽取的對象而導緻重構失敗,涉及到另一個重構(使用get方法而非直接使用私有成員變量),使用此重構即可解決,關注微信公衆号:Java技術棧,回複:idea,擷取一份 IDEA 幹貨教程。
作者:橙味菌
https://juejin.im/post/5e11dd736fb9a047f42e61ad