架構重構之禪

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"引言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Refactoring 一直以來都是項目開發中的熱點和難點,考慮到更通俗的易懂,本文是什麼("},{"type":"text","marks":[{"type":"strong"}],"text":"what"},{"type":"text","text":"),爲什麼("},{"type":"text","marks":[{"type":"strong"}],"text":"why"},{"type":"text","text":")以及怎麼做("},{"type":"text","marks":[{"type":"strong"}],"text":"how"},{"type":"text","text":")的三個點進行展開講解。因爲重構不是獨立的對某一塊代碼優化,而是讓系統以及代碼的相互協調作用表現最佳的改進過程,所以文章的內容可能存在交集的部分,而已理解的情況下,大家可自行跳過。"}]},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"概括"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"重構本質"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"重構是在不創建新的功能方法前提下,改進系統代碼的過程,讓代碼邏輯和架構設計變得更加乾淨和清晰"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"重構意旨"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"重構主要的目的在於解決項目存在的技術債務,將原有的代碼和設計更清晰簡單,提高系統性能。"}]},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"代碼重構(what)"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"重構後的代碼基本具備以下特徵"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼邏輯對於其他項目開發人員清晰簡單;"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"清晰的代碼不包括拷貝重複項"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"乾淨的代碼包括極少的類和方法"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼測試覆蓋了100%"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"技術債務(why)"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"產生技術債務的原因"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"業務壓力,可能需求迭代的速度要求你必須迅速完成功能上線,而沒有時間去完成被忽略的優化工程"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你的上級或者僱主不理解技術債務具有“利益”,因爲隨着債務的累積,技術債務減慢了發展速度。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"無法嚴格按照組件的一致性的規則。通俗的講就是每個功能的改變可能會影響到其他的組件。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"缺乏全面的測試"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個組成員之間缺少相互的交流和反饋"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"缺少清晰的文檔,這樣導致新來的員工不能很快的接手項目"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個長期項目存在多個分支同事開發,這樣導致了後期項目工程後的合併混亂"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"重構項目遲遲被延期,無法進行"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"缺少合理定時的監控"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"技術開發員工甚至不知道如何或者是否需要重構"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":11,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"何時需要開始重構(How)"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"三個規則"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當你實現一個功能的時候,只需要完成實現該項目工程,而不需要考慮後續的複用性"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"面臨做不願意重複的項目事情的時候,而不得不重複"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當你在做一個項目需要重複第三次的時候,這個時候請重構"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在添加新的功能的時候"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果您必須處理別人的髒代碼,請嘗試首先對其進行重構。乾淨的代碼更容易掌握。您不僅會爲自己而且還會爲在您之後使用它的人改進它。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"重構後如何可以更容易的添加新功能,並且使得代碼更加清晰易懂"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當修復bug的時候"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"修復bug的時候,你會自己發現代碼中存在的可優化的項目"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當你的boss讚揚主動重構的行爲時"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在code review的時候"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"code review的時候也許是項目上線發版之前最後一次機會來清楚一些不必要以及不合理的代碼"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"與代碼開發者一起評審的時候,這樣,您可以快速解決簡單的問題,並確定解決更困難的問題的時間"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"如何重構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}}],"text":"在重構之前,請先理解項目並羅列需要重構的清單"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"請把代碼變得更加乾淨清晰:如果你重構後代碼仍然是代碼仍然是不乾淨,模糊不清,對是一些小改的時候,也許看來你是在浪費時間。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"新的功能函數不建議在重構中添加,否則你會將代碼重構的時候變得混亂"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以的測試必須覆蓋重構後100%代碼,需要注意的是你重構測試的時候,有兩種情況會導致你的測試崩潰:"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"重複期間不斷出現bug,然後繼續修復bug"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你所寫的test是比較低級的測試,而無法覆蓋一些特殊場景的測試"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"horizontalrule"},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"underline"},{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"重構的具體實現"},{"type":"text","text":"(detail)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"代碼組織"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"長方法"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很多情況,在原有的方法裏面添加功能比重現創建一個方法,重現的實現全套方法邏輯要簡單的多,因此在項目迭代過程中,我們都會在原來的方法裏面裏增加需要的功能內容"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果方法過長本身內容實現過長的時候,需要將方法裏的內容提取出來改成extraMethod方法,這樣通過方法調用方法"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果在抽取方法的時候,遇到一些當前作用域下的參數不好提取的時候,可以用查詢的方法替換臨時變量"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\ndouble calculateTotal() {\n double basePrice = quantity * itemPrice;\n if (basePrice > 1000) {\n return basePrice * 0.95;\n }\n else {\n return basePrice * 0.98;\n }\n}\n\n// 優化後:\ndouble calculateTotal() {\n if (basePrice() > 1000) {\n return basePrice() * 0.95;\n }\n else {\n return basePrice() * 0.98;\n }\n}\ndouble basePrice() {\n return quantity * itemPrice;\n}\n"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果碰到方法參數過多的情況下,可以將入參組成一個結構體對象。"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"\n// 優化前\nfuncDemo (int a,String b,double c,Mapd,List e){}\n// 優化後\nfuncDemo (Params p){}\n// 參數聚合\nclass Params {\n int a\n String b\n double c\n Mapd\n List e \n}\n/**\n當然這樣做的好處就是方法的入參通過一個對象來描述,這樣就很清晰,\n但是還有一個缺點就是你需要維護多個struct對象結構體,\n因爲每有一個方法需要將入參聚合成對象的時候,\n你就需要創建一個新的對象。\n*/"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果出現循環,請嘗試提取方法。對於條件,請使用分解條件。如果出現循環,請嘗試提取方法。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"性能"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很多人會擔心如果方法過多,這樣會影響性能嗎?其實幾乎在所以情況下,影響微小的可以忽略不計"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"大對象"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"與上述長方法一致,對於開發人員來說,將一個新功能放置在現有類中比在該功能上創建一個新類精神上來看更簡單和輕鬆。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果一個類的對象過長,可以像抽離方法一樣,通過子類來減輕類的長度;"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\nclass Soldier {\n public int health;\n public int damage;\n public int weaponStatus;\n public int getDamage() {\n // ...\n }\n public void attack() {\n // ...\n }\n}\n//優化後\nclass Soldier {\n public int health;\n public Weapon weapon;\n public void attack() {\n // ...\n }\n}\n\nclass Weapon {\n public int damage;\n public int weaponStatus;\n public int getDamage() {\n // ...\n }\n}"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"創建子類,在某些特殊的情況下,類需要實現特殊的方法,而這種情況又是極少的情況下,這個時候可以通過子類來實現,而不是在主類中直接實現過多的方法,並最後可以通過子類中構造方法和或reset()的方法來實現子類屬性的重構"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果有必要羅列客戶端的行爲和使用,這個時候可以通過提取接口的來描述類的功能使用"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果大型類負責圖形界面,則可以嘗試將其某些數據和行爲移至單獨的域對象。這樣做可能需要將某些數據的副本存儲在兩個位置並保持數據的一致性。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"癡迷於基元使用"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"習慣使用原始類型來代替一些小的對象,譬如:匯率 ,電話號碼等"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"習慣用長量做數字信息 譬如:USER_ADMIN_ROLE = 1"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用字符串常量來作爲數組的字段的名稱"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 創建原始字段比創建一個全新的類要容易得多"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"創建對象來代替基元(原始類型或者常量),通常我們會推薦創建枚舉對象類實現"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果一個常量數組裏麪包括不一樣的數據,我們推薦使用對象代替"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//優化前\n//優化前\nString[] row = new String[2];\nrow[0] = \"Liverpool\";\nrow[1] = \"15\";\n//優化後\nPerformance row = new Performance();\nrow.setName(\"Liverpool\");\nrow.setWins(\"15\");"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在碰到字段需要不同的特殊編碼的時候,我們可以將需要處理的字段放入子類,這樣對於不同特殊編碼的情況,我們可以使用子類的多態特徵去實現"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果碰到傳參數需要傳對象的多個基礎屬性的時候,請用整個對象代替"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//優化前\nint low = daysTempRange.getLow();\nint high = daysTempRange.getHigh();\nboolean withinPlan = plan.withinRange(low, high);\n//優化後\nboolean withinPlan = plan.withinRange(daysTempRange);"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"優化好處"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼因爲使用了對象代替了基元,所以變更和更新變得更加靈活"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"閱讀起來更加清晰易懂,在瞭解一個邏輯的時候,變得更集中,而不是到處分散的去找基本類型的定義"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"參數過長"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"過多輪的調用和合並後,在調用新的方法時候,需要之前計算結果當作參數下傳"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個方法如果直接傳多個參數的話,就更加獨立,因爲不存在與其他對象的依賴"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果碰到傳參數需要傳對象的多個基礎屬性的時候,請用整個對象代替"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//優化前\nint low = daysTempRange.getLow();\nint high = daysTempRange.getHigh();\nboolean withinPlan = plan.withinRange(low, high);\n//優化後\nboolean withinPlan = plan.withinRange(daysTempRange);"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在方法內獲取需要查詢的字段,而不是通過值傳遞的方式傳入方法"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"int basePrice = quantity * itemPrice;\ndouble seasonDiscount = this.getSeasonalDiscount();\ndouble fees = this.getFees();\ndouble finalPrice = discountedPrice(basePrice, seasonDiscount, fees);\n\nint basePrice = quantity * itemPrice;\n/**\n*在上述查詢seasonalDiscount和Fees的字段完全可以在discountedPrice內部分方法調用,而是不是通過\n*值傳遞的方式透傳給方法\n*double seasonDiscount = this.getSeasonalDiscount();\n*double fees = this.getFees(); \n*/\ndouble finalPrice = discountedPrice(basePrice);"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"特殊情況"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果因爲使用對象而使得必須依賴其他類的時候,請繼續使用參數的方式傳遞"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"數據塊"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不同代碼的地方經常出現了相同的變量的時候,譬如數據庫配置,Redis配置的。這個時候,我們需要把相同的數據庫可以組織成自己的類。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"創建靜態全局變量,通過使用對象的成員變量來代替原始的數據塊"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\nqueryA(String id){ \n db = initDB(mysqlIp,mysqlHost,userName,passWord)\n db.query(id)\n}\n\ndeleteA(String id){ \n db = initDB(mysqlIp,mysqlHost,userName,passWord)\n db.delete(id)\n}\n//優化後\nclass DBConfig {\n int port\n String host\n String userName\n String Password\n}\n\nqueryA(String id){ \n db = initDB(DBConfig.host,DBConfig.port,DBConfig.userName,DBConfig.Password)\n db.query(id)\n}\n\ndeleteA(String id){ \n db = initDB(DBConfig.host,DBConfig.port,DBConfig.userName,DBConfig.Password)\n db.delete(id)\n}"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"判斷語句"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼中出現一個方法裏面大量的if 或者switch的語句,嚴重的話這樣的判斷語句甚至超過了10個以上。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在項目跌代中,產品的需求在同一個方向做了不同的邏輯,並且隨着版本迭代增加,該方向的個性化邏輯也就逐漸增加"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"將判斷的語句if或switch的代碼部分獨立到一個方法中,通過子方法的方式來處理過長的判斷條件的代碼塊"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通過(策略模式+工程模式)或者反射的模式取代,個人認爲這個是最好的方式,作者力推薦"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\nvoid funcA(String A){\n if A=\"a\"{\n \tdoSomethingA();\n }else if A=\"b\"{\n \tdoSomethingB();\n }else if A=\"c\"{\n \tdoSomethingC();\n }else if A=\"d\"{\n \tdoSomethingD();\n }else {\n \t//default\n }\n}\n\nvoid doSomethingA()\nvoid doSomethingB()\nvoid doSomethingC()\nvoid doSomethingD()\n \n// 優化後\nstatic Map MethodFatory = new HashMap();\n\nstatic{\n\tMethodFatory.put(\"a\",ALogic);\n\tMethodFatory.put(\"b\",BLogic);\n\tMethodFatory.put(\"c\",CLogic);\n\tMethodFatory.put(\"d\",DLogic);\n}\n\n//調用條件方法\nvoid funcA(String A){\n MethodFatory.get(A).doSomething();\n}\n\ninterface Logic {\nvoid doSomething();\n}\n\nclass ALogic implement Logic {\n\tvoid doSomething();\n}\n\nclass BLogic implement Logic {\n\tvoid doSomething();\n}\n\nclass CLogic implement Logic {\n\tvoid doSomething();\n}\n\nclass DLogic implement Logic {\n\tvoid doSomething();\n}\n"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"設置對象參數的時候,請直接提供清晰的方式,譬如對象的成員變量設置"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\nvoid setValue(String name, int value) {\n if (name.equals(\"height\")) {\n height = value;\n return;\n }\n if (name.equals(\"width\")) {\n width = value;\n return;\n }\n Assert.shouldNeverReachHere();\n}\n\n// 優化後\nvoid setHeight(int arg) {\n height = arg;\n}\nvoid setWidth(int arg) {\n width = arg;\n}"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在需要判斷空的條件時候,可以創建子類即空對象來處理"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"//優化前,也許大部分的人都這樣做\nif (customer == null) {\n plan = BillingPlan.basic();\n}\nelse {\n plan = customer.getPlan();\n}\n\n//優化後\n//創建空的之類對象\nclass NullCustomer extends Customer {\n boolean isNull() {\n return true;\n }\n // 空的之類對象負責創建新對象\n Plan getPlan() {\n return new NullPlan();\n }\n}\n\n//如果是空就使用空子類對象\ncustomer = (order.customer != null) ?\n order.customer : new NullCustomer();\n\n// 如果非空直接使用正常對象,如果空則使用空的之類的創建的對象來處理.\nplan = customer.getPlan();"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"臨時變量"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通常開發人員在局部方法中調用下游的函數,且需要傳大量的字段的時候,這個時候他們往往使用局部臨時變量。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"將方法轉換爲一個單獨的類,以便局部變量成爲該類的字段。然後,您可以將方法拆分爲同一類中的多個方法。"}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\nclass Order {\n // ...\n public double price() {\n double primaryBasePrice;\n double secondaryBasePrice;\n double tertiaryBasePrice;\n }\n}\n\n//優化後\nclass Order {\n // ...\n public double price() {\n return new PriceCalculator(this).compute();\n }\n}\n\nclass PriceCalculator {\n private double primaryBasePrice;\n private double secondaryBasePrice;\n private double tertiaryBasePrice;\n \n public PriceCalculator(Order order) {\n }\n \n public double compute() {\n }\n}"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"優化好處"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼結構變得更加清晰和容易組織"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"繼承"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果子類僅使用從其父類繼承的某些方法和屬性,則層次結構是不合理的。不需要的方法可以簡單地不使用或重新定義並釋放異常。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用委派代替繼承,即在子類的構造方法中使用超類的委派構造初始化"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\nclass Manager extends Employee {\n public Manager(String name, String id, int grade) {\n this.name = name;\n this.id = id;\n this.grade = grade;\n }\n // ...\n}\n\n// 優化後\nclass Manager extends Employee {\n public Manager(String name, String id, int grade) {\n super(name, id);\n this.grade = grade;\n }\n // ...\n}\n\n"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在超類中已經有的方法,子類如果不存在特定情況下,不需要重複實現;如果針對不同的場景,超類的方法可以定義成未抽象的方法。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"具有不同接口,卻可相互取代的類"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通俗的說就是存在兩個類,接口名稱不一樣,但是實現的功能基本一致"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開發者在創建接口功能的時候,未了解已經存在一個類實現了該接口需要做的功能"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"提高代碼可讀性,重新定義接口的名稱。接口的名稱必須能夠讓其他人簡單清楚的瞭解接口的大致功能"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果接口之前存在一小部分的功能相同,請將重複的部分抽離成一個子方法,供兩個接口調用"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果已存在重複的實現後,在確定要使用並實現哪種處理方法之後,您可以刪除其中一個重複的類。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"面向對象"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"散佈的到處改動"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有時你只需要給某一個類增加一個字段的時候,而不得不去同時修改其他幾個與本次改動不相關的代碼。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"通常這一類現象產生的原因是代碼的編寫的時候代碼結果不良導致"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於長類需要將類進行拆分"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"class People {\n public int age;\n public int height;\n public int weight;\n public String Name;\n public String getName() {\n // ...\n }\n public void getAge() {\n // ...\n }\n}\n//優化後\nclass PeopleBody {\n public String Name;\n public BodyInfo bodyInfo;\n public String getName() {\n // ...\n }\n}\n\nclass BodyInfo {\n public int age;\n public int height;\n public int weight;\n public int getAge() {\n // ...\n }\n}"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果多個類之間存在一樣的功能方法或者成員變量,我們可以通過繼承來組合這些類。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當一個類的某個方法調用的頻率在其他類中比在自己類中還要高的時候,則創建一個新類,把舊類實現的所以方法都轉移過去,最後並刪除舊類裏的這個方法"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然一個類的成員變量使用頻率在其他類的地方調用更高的時候,則需要創建一個新的類,把這些成員變量轉移過去,最後並刪除舊類裏的這些成員變量。"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 如果該字段是公有的話,這裏需要特殊優化\nclass Person {\n public String name;\n}\n\n/**\n*優化後\n*需要將公有改成私有,這樣修改後以後重構改動將變得更簡單\n*/\nclass Person {\n private String name;\n\n public String getName() {\n return name;\n }\n public void setName(String arg) {\n name = arg;\n }\n}"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"重構好處"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更好的組織"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"減少代碼重複"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"易於維護"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"並行繼承的對象類"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每當爲一個類創建一個子類時,就會發現自己需要爲另一個類創建一個子類"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"隨着項目需求迭代,新的類逐漸增加,後續一些的變動將越來越複雜"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以分兩步對並行類層次結構進行重複數據刪除。首先,使一個層次結構的實例引用另一個層次結構的實例。然後使用上述的“當一個類的某個方法調用的頻率在其他類中比在自己類中還要高的時候,則創建一個新類,把舊類實現的所以方法都轉移過去,最後並刪除舊類裏的這個方法”和“當然一個類的成員變量使用頻率在其他類的地方調用更高的時候,則需要創建一個新的類,把這些成員變量轉移過去,最後並刪除舊類裏的這些成員變量。”的方式解決"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"廢棄的代碼"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"代碼註釋"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一種方法充滿過度性的註釋"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當方法創建者意識到自己的代碼不直觀或不明顯時,通常會出於最佳意圖創建註釋,從而導致了過多的無效註釋,如果你覺得沒有註釋就無法理解代碼片段,請嘗試以無需註釋的方式更改代碼結構。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}}],"text":"最好的註釋就是給方法或者類起一個易懂清晰的名字"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#000000","name":"black"}}],"text":"如果你的註釋是爲了解釋複雜的表達,那麼你需要“提取變量”的方式將代碼結構改成多個子表達的方式"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\nvoid renderBanner() {\n if ((platform.toUpperCase().indexOf(\"MAC\") > -1) &&\n (browser.toUpperCase().indexOf(\"IE\") > -1) &&\n wasInitialized() && resize > 0 )\n {\n // do something\n }\n}\n//優化後\nvoid renderBanner() {\n final boolean isMacOs = platform.toUpperCase().indexOf(\"MAC\") > -1;\n final boolean isIE = browser.toUpperCase().indexOf(\"IE\") > -1;\n final boolean wasResized = resize > 0;\n\n if (isMacOs && isIE && wasInitialized() && wasResized) {\n // do something\n }\n}"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果註釋解釋了一段代碼,那麼你可以把這段代碼抽離成一個方法,而這個新的方法名稱本身就是一種有效而簡單的註釋"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\nvoid printOwing() {\n printBanner();\n\n // Print details.\n System.out.println(\"name: \" + name);\n System.out.println(\"amount: \" + getOutstanding());\n}\n\n// 優化後\nvoid printOwing() {\n printBanner();\n printDetails(getOutstanding());\n}\n\nvoid printDetails(double outstanding) {\n System.out.println(\"name: \" + name);\n System.out.println(\"amount: \" + outstanding);\n}"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果註釋地方的方法已經被抽取了,然而你仍然需要加一些大量的註釋的話,這樣就需要將方法繼續抽離或者重新組織"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果需要聲明有關係統正常運行所必需的狀態的規則,可以使用斷言"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前,我們進程需要處理的\nif (message== null || message.equls(\"\")) { \n throw new IllegalArgumentException(\"輸入信息錯誤!\"); \n} \n\n// 優化後 使用斷言我們可以自己這樣使用\nAssert.hasText((message, \"輸入信息錯誤!\");"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"重複代碼"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"兩塊代碼幾乎完全一致"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當多個程序員同時在同一程序的不同部分上工作時,通常會發生複製。由於他們正在執行不同的任務,因此他們可能不知道自己的同事已經編寫了類似的代碼,這些代碼可以重新用於他們自己的需求。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果一段代碼被兩個類都在使用的話,請這兩個類的這段代碼邏輯抽離成一個新的方法,並刪除原來兩個類的這段代碼塊,然後將這兩個類通過調用新的方法。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果重複的代碼是在類的初始化裏出現,那麼請創建一個超類的構造函數,完成共同的代碼初始化"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\npublic class Manager: Employee \n{\n public Manager(string name, string id, int grade) \n {\n this.name = name;\n this.id = id;\n this.grade = grade;\n }\n // ...\n}\n\n// 優化後\npublic class Manager: Employee \n{\n public Manager(string name, string id, int grade): base(name, id)\n {\n this.grade = grade;\n }\n // ...\n}"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你的代碼功能上大體一樣 但是又非完全一致的時候,將算法結構和相同的步驟移至超類,並將不同步驟的實現留在子類中"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果兩種方法做相同的事情但使用不同的算法,請選擇最佳算法並應用替代算法"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\nstring FoundPerson(string[] people)\n{\n for (int i = 0; i < people.Length; i++) \n {\n if (people[i].Equals(\"Don\"))\n {\n return \"Don\";\n }\n if (people[i].Equals(\"John\"))\n {\n return \"John\";\n }\n if (people[i].Equals(\"Kent\"))\n {\n return \"Kent\";\n }\n }\n return String.Empty;\n}\n// 優化後\nstring FoundPerson(string[] people)\n{\n List candidates = new List() {\"Don\", \"John\", \"Kent\"};\n \n for (int i = 0; i < people.Length; i++) \n {\n if (candidates.Contains(people[i])) \n {\n return people[i];\n }\n }\n \n return String.Empty;\n}"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果存在大量條件表達式並執行相同的代碼(僅在它們的條件中有所不同),請使用合併條件表達式將這些運算符合併爲單個條件,然後使用提取方法將條件放在易於操作的單獨方法中"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\ndouble DisabilityAmount() \n{\n if (seniority < 2) \n {\n return 0;\n }\n if (monthsDisabled > 12) \n {\n return 0;\n }\n if (isPartTime) \n {\n return 0;\n }\n // Compute the disability amount.\n // ...\n}\n// 優化後\ndouble DisabilityAmount()\n{\n if (IsNotEligibleForDisability())\n {\n return 0;\n }\n // Compute the disability amount.\n // ...\n}\n\nbool IsNotEligibleForDisability(){\n if (seniority < 2) \n {\n return true;\n }\n if (monthsDisabled > 12) \n {\n return true;\n }\n if (isPartTime) \n {\n return truetrue;\n }\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果在條件表達式的所有分支中執行相同的代碼:通過使用將相同的代碼放在條件樹之外"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 優化前\nif (IsSpecialDeal()) \n{\n total = price * 0.95;\n Send();\n}\nelse \n{\n total = price * 0.98;\n Send();\n}\n// 優化後\nif (IsSpecialDeal())\n{\n total = price * 0.95;\n}\nelse\n{\n total = price * 0.98;\n}\nSend();"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"優化效果"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"合併重複的代碼可以簡化代碼的結構,並使代碼結構更短。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"代碼更易於簡化且支持成本更低"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"使用較少的類"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"理解和維護一個類的時間和成本是非常高的,如果對於一個經常不實用或者很少值得你去額外關注的話,請刪除這個類"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"經常一些類被設計爲具有全部功能,但經過一些重構後,它變得很小了。也許它旨在支持從未完成的未來開發工作。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果一個類的方法與其他類的功能類似,而且使用的頻率很低的話,請直接把功能移至其他類中,並刪除本類"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於功能很少的子類,可以直接壓縮成一個子類"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"數據類"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據類是指僅包含字段和用於訪問它們的原始方法(獲取器和設置器)的類。這些只是其他類使用的數據的容器。這些類不包含任何其他功能,並且不能獨立地對其擁有的數據進行操作"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當新創建的類僅包含幾個公共字段(甚至可能有少數getter / setter)時,這是很正常的事情。但是對象的真正力量在於它們可以包含行爲類型或對其數據的操作。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果一個類包含公共字段,請使用“封裝字段”將它們隱藏起來以防止直接訪問,並且要求僅通過getter和setter進行訪問。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在類裏的集合成員變量,將getter返回值設爲只讀,並創建用於添加/刪除集合元素的方法,而不是直接操作當前類的數據元素"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於數據類的方法儘可能私有(數據類往往是存在多線程的訪問,所以需要儘可能的不要開放寫的權限,否則就給代碼維護增加了難度和成本)"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"數據類只有在初始化的時候,可以設置其值,其他時刻無法修改。(數據類往往是存在多線程的訪問,所以需要儘可能的不要開放寫的權限,否則就給代碼維護增加了難度和成本)"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"無效的代碼"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不再使用變量,參數,字段,方法或類。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當軟件要求發生變化或進行了更正時,沒有人有時間清理舊代碼"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"刪!刪!刪!以前沒有svn或git的時候,有些書籍或文章說代碼不用註釋而不是刪除,而現在看來有了版本控制,沒用的代碼直接刪除!"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於不必要的類,如果使用子類或超類,則可以應用內聯類或摺疊層次結構"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果方法中存在無效的參數的時候也請直接刪除"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"投機代碼"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"總有一些用不上的類,方法以及變量或參數"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有時會以“以防萬一”的方式創建代碼,以支持從未實現的預期未來功能。結果,創建的代碼幾乎沒有被使用,到後來維護變得難以理解"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於很少使用的代碼,嘗試合併子類或者方法"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於沒有必要聲明的類可以將其成員變量移動到與其關聯的內鏈類,並刪除當前類"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於很少用方法嘗試,使用內鏈方法避免它們"}]}]}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" // 優化前\nclass PizzaDelivery {\n \n int getRating() {\n return moreThanFiveLateDeliveries() ? 2 : 1;\n }\n boolean moreThanFiveLateDeliveries() {\n return numberOfLateDeliveries > 5;\n }\n}\n// 優化後\nclass PizzaDelivery {\n int getRating() {\n return numberOfLateDeliveries > 5 ? 2 : 1;\n }\n}"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"方法用不上的參數,應該直接刪除"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用不上的成員變量,可以刪除"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"耦合"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"功能轉移"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當前類方法訪問另一個對象的數據比訪問其自身的數據更多"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"將過多的字段定義在數據類中,在這種情況下,您可能還希望將對數據的操作移至此類。"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在使用該方法最多的類中創建一個新方法,然後將代碼從舊方法移至該位置。將原始方法的代碼轉換爲對另一個類中新方法的引用,否則將其完全刪除"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果僅方法的一部分訪問另一個對象的數據,請將這部分代碼抽取成方法獨立出來,通過調用方式來訪問"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果一個方法使用其他幾個類的方法,則首先確定哪個類包含大多數使用的數據。然後將方法與其他數據一起放在此類中。或者,使用提取方法將方法分爲幾個部分,這些部分可以放在不同類別的不同位置"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"優化效果"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"減少重複代碼"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"良好的代碼組織結構"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"不合理的組織關係"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個類使用另一個類的內部的成員變量和方法"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"生產原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"開發中把所有的集中點都放到一個類中,這樣導致其他的類與該類有了過多的密切聯繫,譬如依賴該類的方法和該類的成員變量"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最簡單的方法就是拆分類的方法和成員變量,並轉移到一個公共的組件,這樣類與類之間的之間類就存在較少的依賴"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"另一種解決的方案就是創建代理,譬如對象A需要方法呢對象B的方法,而不直接訪問,而是通過訪問大代理客戶端,這樣對象A就不需要過度關對象B的具體實現和改動"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果兩個類是相互依存或者無法剝離,請嘗試合併或者歸併成一個對象,或者從功能上實現減少不必要的相互依存關係"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果依賴關係是存在子類和超類中的,請直接用繼承來代替代理"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"優化效果"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"改善代碼組織結構"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"簡化代碼維護和理解"}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"消息傳遞鏈子"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在代碼中,也許經常看到funcA()->funcB()->func()C-funcD(),這樣串行的依賴"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當客戶端請求另一個對象,該對象又請求另一個對象,依此類推,就會發生消息鏈。這些鏈意味着客戶端依賴於沿類結構的導航。這些關係中的任何更改都需要修改客戶端"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"刪除這樣的調用鏈,在類A中創建一個新方法,該方法將調用委派給對象B(使用代理)"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有時最好考慮一下爲什麼要使用最終對象。也許將抽取方法(具體代碼請參考“"},{"type":"text","marks":[{"type":"strong"}],"text":"長方法"},{"type":"text","text":"”)此功能並通過移動方法裏的邏輯,將其移動到鏈的開頭是有意義的。有時最好考慮一下爲什麼要使用最終對象"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用消息中間件來解決這樣串行耦合度高的邏輯"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"優化效果"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"減少類與類之間的依賴"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"減少大量無效對的代碼"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"代理"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"常見現象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果一個類只有一個簡單的方法,調用方式卻是通過一個代理類給其他人提供調用"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"產生原因"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"盲目過度的想消除類之間的串行調用關係"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個類的功能正在逐步轉移到另一個類中,而該類逐漸是一個空殼,而除了代理的作用"}]}]}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"解決方案"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果一個方法的大部分的方法都是代理到另一個類的話,刪除代類,強直接調用另一個類的最終方法方法"}]},{"type":"heading","attrs":{"align":null,"level":5},"content":[{"type":"text","text":"優化效果"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"減少代碼體積"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"參考文獻:"},{"type":"link","attrs":{"href":"https://refactoringguru.cn/store","title":null},"content":[{"type":"text","text":"https://refactoringguru.cn/store"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"騰訊雲大量崗位職位招聘,歡迎大家來撩:[email protected]"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章