JAVA代碼重構(gòu)--改善既有代碼的設(shè)計(jì)
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
76套java從入門到精通實(shí)戰(zhàn)課程分享
JAVA代碼重構(gòu)–改善既有代碼的設(shè)計(jì)(一)
本文主要借鑒了<重構(gòu) 改善既有代碼的設(shè)計(jì)>與<設(shè)計(jì)模式>這兩本書;
主要解釋重構(gòu)的原理(principles)和最佳實(shí)踐方式(best practices),并指出何時(shí)何地你應(yīng)該開始挖掘你的代碼以求改善。
<重構(gòu) 改善既有代碼的設(shè)計(jì)>核心是一份完整的重構(gòu)名錄(catalog of refactoring),其中每一項(xiàng)都介紹一種經(jīng)過實(shí)證的代碼變換手法(code transformation)的動機(jī)和技術(shù)。某些項(xiàng)目如Extract Method和Move Field看起來可能很淺顯,但不要掉以輕心,因?yàn)槔斫膺@類技術(shù)正是有條不紊地進(jìn)行重構(gòu)的關(guān)鍵。本書所提的這些重構(gòu)準(zhǔn)則將幫助你一次一小步地修改你的代碼,這就減少了過程中的風(fēng)險(xiǎn)。很快你就會把這些重構(gòu)準(zhǔn)則和其名稱加入自己的開發(fā)詞典中,并且朗朗上口。
重構(gòu)重點(diǎn)
1.Duplicated Code(重復(fù)代碼)
同一個(gè)類的兩個(gè)函數(shù)含有相同的表達(dá)式,需要將重復(fù)的這段代碼提出來,讓這兩個(gè)函數(shù)都調(diào)用這段代碼,兩個(gè)互為兄弟的子類內(nèi)含相同表達(dá)式,需要將代碼提煉出來放入父類中;
如果兩個(gè)毫不相關(guān)的類出現(xiàn)Duplicated Code,需要將重復(fù)代碼提煉到一個(gè)獨(dú)立類中,然后在另一個(gè)類內(nèi)使用這個(gè)新類,抑或這個(gè)函數(shù)可能屬于第三個(gè)類,而另兩個(gè)類應(yīng)該引用這第三個(gè)類;
2.Long Method(過長函數(shù))
擁有短函數(shù)的對象會活得比較好、比較長。解釋能力、共享能力、選擇能力——都是由小型函數(shù)支持的。每當(dāng)感覺需要以注釋來說明點(diǎn)什么的時(shí)候,就把需要說明的東西寫進(jìn)一個(gè)獨(dú)立函數(shù)中,并以其用途命名
3.Large Class(過大的類)
一個(gè)類如果擁有太多代碼,就需要將其拆分,可以先確定客戶端如何使用它們,然后為每一種使用方式提煉出一個(gè)接口;
產(chǎn)生條件:這個(gè)類實(shí)例變量太多,必然會有Duplicated Code(重復(fù)代碼) ;類內(nèi)如果有太多代碼,也會產(chǎn)生Duplicated Code,讓整個(gè)類看起來混亂并最終走向死亡。
4.Long Parameter List(過長參數(shù)列)
太長的參數(shù)列難以理解,太多參數(shù)會造成前后不一致、不易使用,而且一旦需要更多數(shù)據(jù),就不得不修改它,可以把函數(shù)所需要的東西通過對象傳入;
一旦你需要更多的數(shù)據(jù),你就不得不去修改它。相反如果你通過傳入對象,首先你的參數(shù)列表就很短,其次如果你想增加別的變量,會有可能只需要在函數(shù)中對這個(gè)參數(shù)對象多加一次請求就行了。
如果向已有的對象發(fā)送一條請求可以取代一個(gè)參數(shù),那么你應(yīng)該使用Replace Parameter with Method。注意是已有的參數(shù),不是不存在的參數(shù)。這個(gè)需要理解一下,已有的參數(shù)就是函數(shù)宿主類中的某一個(gè)對象字段,也可能是函數(shù)本身存在另一個(gè)對象參數(shù),讓這個(gè)對象來替換它。如果某些數(shù)據(jù)缺乏合理的對象歸屬??梢允褂肐ntroduce Parameter Object來為它們制造一個(gè)“參數(shù)對象”。
5.Divergent Change(發(fā)散式變化)
如果某個(gè)類經(jīng)常因?yàn)椴煌脑蛟诓煌姆较蛏习l(fā)生變化,就會出現(xiàn)Divergent Change,如增加一個(gè)功能需要修改多處,這時(shí)應(yīng)該把針對某一外界變化的所有相應(yīng)修改都放在一個(gè)類中;時(shí)刻要記住這么一句話:針對某一外界變化的所有相應(yīng)修改,都應(yīng)該產(chǎn)生在單一類中,而這個(gè)新類中的所有內(nèi)容都應(yīng)該反應(yīng)此變化。
6.Shotgun Surgery(霰彈式修改)
如果每遇到某種變化,就必須在許多不同的類內(nèi)做出許多小修改,這就是Shotgun Surgery,應(yīng)該把需要修改的代碼放進(jìn)同一個(gè)類,如果沒有合適的類就創(chuàng)建一個(gè)
7.Feature Envy(依戀情結(jié))
如果一個(gè)函數(shù)為了計(jì)算某個(gè)值,需要用到幾個(gè)類的數(shù)據(jù),就把函數(shù)移到最多被此函數(shù)使用的數(shù)據(jù)的類中;面向?qū)ο蠹夹g(shù)就是將數(shù)據(jù)和行為包裝在一起。一個(gè)經(jīng)典的壞味道的場景就是函數(shù)都某個(gè)類的興趣高過對自己所處類的興趣,往往焦點(diǎn)就是數(shù)據(jù)。很多時(shí)候我們可以看到這種場景,類A的中的函數(shù)為了進(jìn)行計(jì)算獲取了類B中幾乎一半的數(shù)據(jù),面對這種情況,其實(shí)很簡單,就是使用Move Method將這個(gè)函數(shù)直接移到B中去,然后讓類A的調(diào)用點(diǎn)就調(diào)用類B的這個(gè)函數(shù)。如果一個(gè)函數(shù)中,只有一部分受這種“依戀之苦”,你應(yīng)該用Extract Method把這一部分提煉出來,然后通過Move Method把這個(gè)提煉的函數(shù)移動到他所依戀的類中去。如果出現(xiàn)一個(gè)函數(shù)需要用到幾個(gè)類的時(shí)候,我們會很難判斷究竟應(yīng)該把它放哪。這個(gè)時(shí)候有個(gè)小技巧你只要記住,這個(gè)函數(shù)獲取哪個(gè)類的數(shù)據(jù)最多,就把這個(gè)函數(shù)移動到哪個(gè)類中去。當(dāng)然面對這種多重以來,你也可以用Extract Method將這個(gè)函數(shù)分解成一系列小函數(shù)然后移動到他們對應(yīng)的需要的類中去也可以輕松完成。
8.Data Clumps(數(shù)據(jù)泥團(tuán))
總是綁在一起出現(xiàn)的數(shù)據(jù)應(yīng)該擁有屬于它們自己的對象,評判方法是:刪掉眾多數(shù)據(jù)中的一項(xiàng),如果其他數(shù)據(jù)沒有意義了,那就應(yīng)該為它們產(chǎn)生一個(gè)新對象;可以使用復(fù)用,讓他們擁有屬于他們自己的行為,簡化參數(shù)列表
9.Primitive Obsession(基本類型偏執(zhí))
大多數(shù)編程環(huán)境都有兩種數(shù)據(jù):結(jié)構(gòu)類型允許你將數(shù)據(jù)組織成有意義的形式;基本類型則是構(gòu)成結(jié)構(gòu)類型的積木塊。結(jié)構(gòu)總是會帶來一定的額外開銷,它們可能代表著數(shù)據(jù)庫中的表,如果只為做一兩件事而創(chuàng)建結(jié)構(gòu)類型也可能顯得太麻煩;
10.Switch Statements(switch)
文中作者用了“驚悚”來形容swtich語句,的確,面向?qū)ο笾袎焊筒恍枰嬖趕wtich,多態(tài)給了比swtich更優(yōu)雅的解法。swtich語句本身就代表了重復(fù),你在需要做類型判斷的時(shí)候你就需要寫這一長串的swtich不說,當(dāng)你要增加新的類型你就需要尋找這些所有的swtich,維護(hù)工作非常困難。大多數(shù)時(shí)候,當(dāng)你一看到swtich語句,你就應(yīng)該考慮用多態(tài)來優(yōu)雅的解決。問題是這個(gè)多態(tài)應(yīng)該出現(xiàn)在哪 ?swtich語句常常跟類型碼有關(guān),你所要做的就是尋找與這些類型碼有關(guān)的函數(shù)或類。應(yīng)該先用Extract Method把這個(gè)swtich語句提煉到一個(gè)獨(dú)立函數(shù)中去,然后運(yùn)用Move Method把它搬移到需要多態(tài)性的那個(gè)類里。接下來你需要考慮是否使用Replace Type Code wtih Subclass或者Replace Type Code with State/Strategy。一旦這樣的繼承結(jié)構(gòu)完成之后,你就可以運(yùn)用Replace Condiional with Polymorphism來優(yōu)雅的進(jìn)行解決了。
11. Parallel Inheritance Hierarchies(平行繼承體系)
Parallel Inheritance Hierarchies其實(shí)是Shotgun Surgery的特殊情況。意思就是當(dāng)你為某一個(gè)類增加子類的同時(shí)你必須為別的類同時(shí)增加子類。有個(gè)簡單辦法可以判斷,當(dāng)你發(fā)現(xiàn)某個(gè)類的繼承體系前綴和另外一個(gè)繼承體系前者完全相同,你便聞到了這股壞味道。
解決這個(gè)辦法的一般策略就是讓一個(gè)繼承體系的實(shí)例去引用另外一個(gè)繼承體系的實(shí)例。然后不斷運(yùn)用Move Method和Move Field到被引用端,你就可以將引用端的繼承體系完全打破,做到被引用端單一的繼承體系。
12.Lazy Class(冗贅類)
雖然面向?qū)ο笫澜鐜Ыo我們對象的魅力,但并不是類越多就越好。雖然加入間接層可以帶來各種方便,但所有的類都是需要人能夠去理解和維護(hù)的。對于那些實(shí)際作用不大的類,或者因?yàn)槟承┲貥?gòu)原因讓它變得沒有價(jià)值的時(shí)候,或開發(fā)者事前規(guī)劃了某些類來應(yīng)對變化,但實(shí)際上并沒有發(fā)生這些變化。不論上述哪一種原因,就讓這個(gè)類消失好了,這樣減少你的工作量的同時(shí)也在減少別人的工作量,因?yàn)楹苡锌赡軐砭S護(hù)代碼的人還是你自己。如果子類沒有做足夠的工作,可以運(yùn)用Collapse Hierarchy來打破繼承體系,對于幾乎沒有用的組件,你可以運(yùn)用Inline Class來對付它們。
對象技術(shù)的新手通常不愿意在小任務(wù)上運(yùn)用小對象,但是對象的一個(gè)極大的價(jià)值在于:它們模糊(甚至打破)了橫亙于基本數(shù)據(jù)和體積較大的類之間的界限
————————————————
版權(quán)聲明:本文為CSDN博主「Haqiu.Hwang」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:
https://blog.csdn.net/qq_38658567/article/details/81914759
鋒哥最新SpringCloud分布式電商秒殺課程發(fā)布
??????
??長按上方微信二維碼 2 秒
感謝點(diǎn)贊支持下哈 
