??如果1個人沒有聽說過《重構》這本書,那末他1定不敢說自己是程序員;如果1個人沒有瀏覽過《重構》這本書,那末很難想象他會是1名優秀的程序員。這本書是很多公司要求Java程序員必讀的3本書之1(另外兩本書是《Java編程思想》和《Effective Java》),其實無關編程語言,是程序員就可以夠從這本書中受益。
??何謂重構?重構是對軟件內部結構的1種調劑,目的是在不改變軟件可視察行動的條件下,提高其可理解性,下降修改本錢。重構是用微小的步伐修改程序,在這個進程中也能夠很容易的發現程序中的毛病。重構的時機可以是添加功能時,也能夠是修補毛病時,還可以是復審代碼時。重構的目標是讓代碼容易瀏覽、所有邏輯都在唯1地點指定、新的改動不會危及現有行動、盡量簡單的表達邏輯。
??這本書我個人最喜歡的第3章 - “代碼的壞味道”,由于我喜歡在寫完代碼后去思考我的代碼中有無這些壞味道,然后再去想想應當如何重構代碼。這本書的作者是世界級的軟件開發大師Martin Fowler,他也被譽為軟件開發“教父”,同時他還是敏捷開發的開創人之1。Martin Fowler編寫了很多極好的書籍,包括《企業利用架構模式》、《領域特定語言》、《NoSQL精粹》、《分析模式:可重用對象模型》等。Martin Fowler給出的代碼的壞味道包括:
- Duplicated Code(重復代碼):“代碼有很多中壞味道,重復是最壞的1種”,這句話我常常講給自己的學生聽,但是他們真正領悟并踐行這句話的人卻不多。1個類中的兩個方法有重復代碼,那末1定可以通過抽取方法的方式將重復代碼放到另外一個方法中以供調用;兩個互為兄弟的子類中如果有重復代碼可以將其重復代碼抽取到父類中;兩個沒有關系的類中如果有重復代碼,那末可以重新抽取1個類將重復代碼放到這個第3方類中。
- Long Method(長的方法):程序越長理解起來就越困難,這已是常識了,使用短小的方法首先符合高內聚的要求,同時也能夠給通過給方法起1個好的名字來幫助理解方法的作用。如果感覺到方法的某個地方需要注釋來講明甚么,那末可以把這些東西放入1個獨立的方法中,并以用處(注意不是實現手法)來命名方法。
- Large Class(巨大的類):如果希望寫1個類來做很多的事情,那末終究必將致使重復和混亂的代碼。類的設計應當遵守單1職責原則(SRP)。重構1個巨大的類可使用抽取接口的方式來弄清楚這個類應當如何分解。
- Long Parameter List(長參數列表):這個對做過Windows編程或用過MFC(Microsoft Foundation Class)的程序員來講再熟習不過了,Windows函數和MFC中的方法那些長得變態的參數列表對程序員來講都是噩夢。重構的方式很多,比較常見的是將相干的參數組織成1個對象來替換掉這些參數。
- Divergent Change(分散的可變性)和Shotgun Surgery(散彈式手術):這兩種壞味道前者講的是新功能難以加入,后者說的是某種變化會引發多個細節的修改。簡單的說如果程序中的可變因素散落在代碼的各個角落中,那末代碼的保護將是1場噩夢。重構的方法是找到特定緣由釀成的所有變化,然后將它們抽取到另外一個類中。設計模式中的橋梁模式就是為了解決這1問題而提供的解決方案。
- Feature Envy:這個真沒想到如何翻譯會比較容易理解,簡單的說就是1個方法從另外一個類的對象那里獲得許多的值,重構的方案是將該方法移到另外一個類中。聽起來很簡單,但是在實踐的時候卻常常會忘了這么做。
- Data Clumps(數據群集):狀態類似于長參數列表。
- Primitive Obsession(基本類型偏執)。1個類中如果有很多基本類型的成員,通常可以斟酌將不同的基本類型分散組裝成對象,就像Hibernate中的組合映照那樣,將1個類的對象嵌入到另外一個類中作為其成員而不是只寫1個類,里面有很多基本數據類型的成員。
- Switch Statements(重復的switch語句):面向對象程序的1個明顯特點就是用多態替換掉switch結構,由于這類switch結構會在多個地方重復。
- Parallel Inheritance Hierarchies(平行繼承結構):情況跟Shortgun Surgery差不多,可使用橋梁模式進行重構。
- Lazy Class(冗余類):如果1個類不值得存在,那末它就應當消失。
- Speculative Generality(投機通用性):如果你的抽象類、拜托、方法的參數沒有實際的作用,那末就應當被移除掉。
- Temporary Field(臨時字段):類中某個字段只為某些特殊情況而設置。
- Message Chains(消息鏈):我個人并沒有感覺到這個有多么壞。
- Middle Man(中間人):如果1個類的很多功能都通過拜托給其他類來完成,那末就不如去掉這些中間人直接和真正負責的對象打交道。
- Inappropriate Intimacy(過于密切):使用繼承復用代碼會常常性的引發這類問題,由于子類對父類的了解總是超過后者的主觀欲望,如果你覺得這個孩子可以獨立生活了,就應當讓它離開繼承體系,這1點跟面向對象設計原則中的合成聚合復用原則不謀而合。
- Alternative Classes with Different Interfaces(異曲同工):兩個方法做同1件事情卻有著不同的簽名。
- Incomplete Library Class(不完全類庫)。
- Data Class(數據類):類的退化結構。我們在分層開發中常常使用的失血模型(事務腳本模式)中的業務實體不就是數據類嗎,這明顯與面向對象的思想是背道而馳的。
- Refused Bequest(謝絕遺產):如果子類復用了父類的行動,又不愿意支持父類的接口,可以斟酌用合成關系聚合關系取代繼承關系來消除這類壞味道。
- Comments(注釋劣質代碼):注釋不是用來補救劣質代碼的,事實上如果我們去除代碼中的所有壞味道,當劣質代碼都被移除的時候,注釋已變很多余,由于代碼已講清楚了1切。
??完全根除代碼中這些壞味道的方法在《重構》1書的第6章到第102章,提供了約70條重構建議,其中1部份經常使用的重構建議在IDE的重構菜單中也能找到。Eclipse和IntelliJ的重構菜單分別以下面兩張圖所示。
Eclipse的重構菜單:
IntelliJ的重構菜單: