最近接手一個項目,源代碼的架構和許多設計都有壞的味道。 想要重構,但是自己並沒有足夠的底氣.
一、重構的糾結:
(1)現有代碼可用,你重構后是否會比現在更有效率;
(2)項目進度比較緊,你是否要抽出時間做這種沒有KPI的工作;
(3)你重構后,別人需要重新閱讀你的源代碼,給同事帶來了重新學習代碼的工作量;
(4)項目是否能夠持續,如果沒有需求,不用了,你還重構什么?
(5)你是否要在這個公司待很久,等重構完后,你可能都不在了。
二、如果不重構,確實會給開發帶來很大困難:
原代碼就像是一個打滿了補丁的棉襖,它可以保暖,但是很難定位到哪里漏風,即使定位到了,不過是新打些補丁,但是縫縫補補的工作可能沒有盡頭。
(1)修改很耗精力;
(2)BUG花樣迭出
(3)擴展性差,持續開發跟進需求很難;
(4)應變能力差,牽一發動全身。
重構或不重構,這是個問題,直到看了《重構 改善既有代碼的設計》,給了我很大啟發。粗略看了一遍,道理明白了一些,我之前的想法應該叫做重寫而不是重構。
重構是逐步改善的過程,是重寫與打補丁的中間選項。
當然看完書之后,我還是選擇了重寫,因為項目還不是很大,重寫做起來工作量更小一些。
重構的核心還是使代碼盡量遵循設計模式的六大原則:
(1)單一職責原則
(2)里氏替換原則
(3)依賴倒置原則
(4)接口隔離原則
(5)迪米特法則
(6)開閉原則
重構中用到的方法,是寫代碼過程中很好的參照。方法都寫在2-13章的目錄里了,意思比較明顯,閑來的時候看看,也大有裨益。
第2章 重構原則 2.1 何謂重構53 2.2 為何重構55 2.3 何時重構57 2.4 怎么對經理說60 2.5 重構的難題62 2.6 重構與設計66 2.7 重構與性能69 2.8 重構起源何處71 第3章 代碼的壞味道 3.1 DuplicatedCode(重復代碼)76 3.2 LongMethod(過長函數)76 3.3 LargeClass(過大的類)78 3.4 LongParameterList(過長參數列)78 3.5 DivergentChange(發散式變化)79 3.6 ShotgunSurgery(霰彈式修改)80 3.7 FeatureEnvy(依戀情結)80 3.8 DataClumps(數據泥團)81 3.9 PrimitiveObsession(基本類型偏執)81 3.10 SwitchStatements(switch驚悚現身)82 3.11 ParallelInheritanceHierarchies(平行繼承體系)83 3.12 LazyClass(冗贅類)83 3.13 SpeculativeGenerality(誇誇其談未來性)83 3.14 TemporaryField(令人迷惑的暫時字段)84 3.15 MessageChains(過度耦合的消息鏈)84 3.16 MiddleMan(中間人)85 3.17 InappropriateIntimacy(狎昵關系)85 3.18 AlternativeClasseswithDifferentInterfaces(異曲同工的類)85 3.19 IncompleteLibraryClass(不完美的庫類)86 3.20 DataClass(純稚的數據類)86 3.21 RefusedBequest(被拒絕的遺贈)87 3.22 Comments(過多的注釋)87 第4章 構築測試體系 4.1 自測試代碼的價值89 4.2 JUnit測試框架91 4.3 添加更多測試97 第5章 重構列表 5.1 重構的記錄格式103 5.2 尋找引用點105 5.3 這些重構手法有多成熟106 第6章 重新組織函數 6.1 ExtractMethod(提煉函數)110 6.2 InlineMethod(內聯函數)117 6.3 InlineTemp(內聯臨時變量)119 6.4 ReplaceTempwithQuery(以查詢取代臨時變量)120 6.5 IntroduceExplainingVariable(引入解釋性變量)124 6.6 SplitTemporaryVariable(分解臨時變量)128 6.7 RemoveAssignmentstoParameters(移除對參數的賦值)131 6.8 ReplaceMethodwithMethodObject(以函數對象取代函數)135 6.9 SubstituteAlgorithm(替換算法)139 第7章 在對象之間搬移特性 7.1 MoveMethod(搬移函數)142 7.2 MoveField(搬移字段)146 7.3 ExtractClass(提煉類)149 7.4 InlineClass(將類內聯化)154 7.5 HideDelegate(隱藏“委托關系”)157 7.6 RemoveMiddleMan(移除中間人)160 7.7 IntroduceForeignMethod(引入外加函數)162 7.8 IntroduceLocalExtension(引入本地擴展)164 第8章 重新組織數據 8.1 SelfEncapsulateField(自封裝字段)171 8.2 ReplaceDataValuewithObject(以對象取代數據值)175 8.3 ChangeValuetoReference(將值對象改為引用對象)179 8.4 ChangeReferencetoValue(將引用對象改為值對象)183 8.5 ReplaceArraywithObject(以對象取代數組)186 8.6 DuplicateObservedData(復制“被監視數據”)189 8.7 ChangeUnidirectionalAssociationtoBidirectional(將單向關聯改為雙向關聯)197 8.8 ChangeBidirectionalAssociationtoUnidirectional(將雙向關聯改為單向關聯)200 8.9 ReplaceMagicNumberwithSymbolicConstant(以字面常量取代魔法數)204 8.10 EncapsulateField(封裝字段)206 8.11 EncapsulateCollection(封裝集合)208 8.12 ReplaceRecordwithDataClass(以數據類取代記錄)217 8.13 ReplaceTypeCodewithClass(以類取代類型碼)218 8.14 ReplaceTypeCodewithSubclasses(以子類取代類型碼)223 8.15 ReplaceTypeCodewithState/Strategy(以State/Strategy取代類型碼)227 8.16 ReplaceSubclasswithFields(以字段取代子類)232 第9章 簡化條件表達式 9.1 DecomposeConditional(分解條件表達式)238 9.2 ConsolidateConditionalExpression(合並條件表達式)240 9.3 ConsolidateDuplicateConditionalFragments(合並重復的條件片段)243 9.4 RemoveControlFlag(移除控制標記)245 9.5 ReplaceNestedConditionalwithGuardClauses(以衛語句取代嵌套條件表達式)250 9.6 ReplaceConditionalwithPolymorphism(以多態取代條件表達式)255 9.7 IntroduceNullObject(引入Null對象)260 9.8 IntroduceAssertion(引入斷言)267 第10章 簡化函數調用 10.1 RenameMethod(函數改名)273 10.2 AddParameter(添加參數)275 10.3 RemoveParameter(移除參數)277 10.4 SeparateQueryfromModifier(將查詢函數和修改函數分離)279 10.5 ParameterizeMethod(令函數攜帶參數)283 10.6 ReplaceParameterwithExplicitMethods(以明確函數取代參數)285 10.7 PreserveWholeObject(保持對象完整)288 10.8 ReplaceParameterwithMethods(以函數取代參數)292 10.9 IntroduceParameterObject(引入參數對象)295 10.10 RemoveSettingMethod(移除設值函數)300 10.11 HideMethod(隱藏函數)303 10.12 ReplaceConstructorwithFactoryMethod(以工廠函數取代構造函數)304 10.13 EncapsulateDowncast(封裝向下轉型)308 10.14 ReplaceErrorCodewithException(以異常取代錯誤碼)310 10.15 ReplaceExceptionwithTest(以測試取代異常)315 第11章 處理概括關系 11.1 PullUpField(字段上移)320 11.2 PullUpMethod(函數上移)322 11.3 PullUpConstructorBody(構造函數本體上移)325 11.4 PushDownMethod(函數下移)328 11.5 PushDownField(字段下移)329 11.6 ExtractSubclass(提煉子類)330 11.7 Extract Superclass (提煉超類) 336 11.8 Extract Interface (提煉接口) 341 11.9 Collapse Hierarchy (折疊繼承體系) 344 11.10 FormTemplateMethod(塑造模板函數) 345 11.11 Replace Inheritance with Delegation(以委托取代繼承) 352 11.12 Replace Delegation with Inheritance (以繼承取代委托) 355 第12章 大型重構 12.1 Tease Apart Inheritance (梳理並分解繼承體系) 362 12.2 Convert Procedural Design to Objects (將過程化設計轉化為對象設計) 368 12.3 Separate Domain from Presentation (將領域和表述/顯示分離) 370 12.4 Extract Hierarchy (提煉繼承體系) 375