譯者 | 劉汪洋
審校 | 重樓
Java 代碼重構是一種在不影響代碼外部行為的前提下進行的代碼優化,它通過漸進和小規模的優化來改善現有代碼的結構和質量。重構的目標是提高代碼的可讀性、性能、可維護性和效率等。
Martin Fowler 是這個領域的權威的大牛和非常高產的作家,他在多篇文章和書籍中探討了代碼設計和重構的主題。在他的作品《重構:改善既有代碼的設計》中,他精辟地解釋了重構的本質:
_“重構是在不改變代碼外在行為的前提下,對代碼做出修改,以改進程序內在結構的過程。重構是一種經過千錘百煉形成的有條不紊的程序整理方法,可以最大限度地減少整理過程中引入的錯誤幾率。其核心是不斷進行一些小的優化,每個優化看似不起眼,但積少成多,效果顯著。” ——Martin Fowler
在進行 Java 代碼重構時,可以考慮以下常見的優化措施:
為變量和方法選擇具有代表性的名稱是增強代碼可讀性的重要方法。
代碼的可讀性是構建高質量代碼庫的關鍵要素之一。易讀的代碼能夠清晰地表達其目的,而難以理解的代碼則會增加重構過程中出現錯誤的風險。采用有意義的變量和方法名稱可以減少注釋的需求,并降低溝通成本。
// 重構前int d = 30; // 天數int h = 24; // 一天的小時數// 重構后int daysInMonth = 30;int hoursInDay = 24;
在 Java 代碼重構技術中,方法的提取是一種常見而實用的策略。當一個方法變得過長和過于復雜時,通過提取部分功能到一個新的方法中能夠使原方法更簡潔和易讀。這不僅使代碼更具可維護性,還提高了其可重用性。
假設你有一個簡單的類,用于處理訂單并計算小計、稅費和總費用。
public class OrderProcessor { private List<Item> items; private double taxRate; public double processOrder() { double subtotal = 0; for (Item item : items) { subtotal += item.getPrice(); } double totalTax = subtotal * taxRate; double totalCost = subtotal + totalTax; return totalCost; }}
你可以將該代碼重構,把計算小計、稅費和總費用的代碼分別提取到 calculateSubtotal、calculateTax 和 calculateTotalCost 三個獨立的方法中,從而使類更加易讀、模塊化和可重用。
public class OrderProcessor { private List<Item> items; private double taxRate; public double processOrder() { double subtotal = calculateSubtotal(); double totalTax = calculateTax(subtotal); return calculateTotalCost(subtotal, totalTax); } private double calculateSubtotal() { double subtotal = 0; for (Item item : items) { subtotal += item.getPrice(); } return subtotal; } private double calculateTax(double subtotal) { return subtotal * taxRate; } private double calculateTotalCost(double subtotal, double totalTax) { return subtotal + totalTax; }}
“魔法”數字和字符串是指直接硬編碼在代碼中的值。這種做法不僅會降低代碼的可維護性,還可能因輸入錯誤而導致結果不一致和錯誤的增多。為了避免這樣的問題,你應當避免使用硬編碼的值,而是通過使用具有清晰描述性的常量來重構你的代碼。
// 重構前if (status == 1) { // ... 活躍狀態的代碼 ...}// 重構后public static final int ACTIVE_STATUS = 1;if (status == ACTIVE_STATUS) { // ... 活躍狀態的代碼 ...}
代碼復用是指刪除代碼庫中多處出現的重復或相似的代碼段。這樣的代碼不僅降低了代碼質量和效率,還可能導致 bug 更加頻繁的出現和代碼庫變得更加復雜。因此,開發人員通常會對這類代碼感到反感。為了優化代碼,我們可以考慮提取重復部分來創建可復用的方法或函數,同時確保重構過程中保持原有代碼的功能和邏輯。
public class NumberProcessor { // 計算總和 public int calculateTotal(int[] numbers) { int total = 0; for (int i = 0; i < numbers.length; i++) { total += numbers[i]; } return total; } // 計算平均值 public double calculateAverage(int[] numbers) { int total = 0; for (int i = 0; i < numbers.length; i++) { total += numbers[i]; } double average = (double) total / numbers.length; return average; }}
public class NumberProcessor { // 計算總和 public int calculateSum(int[] numbers) { int total = 0; for (int i = 0; i < numbers.length; i++) { total += numbers[i]; } return total; } // 計算總和 public int calculateTotal(int[] numbers) { return calculateSum(numbers); } // 計算平均值 public double calculateAverage(int[] numbers) { int total = calculateSum(numbers); double average = (double) total / numbers.length; return average; }}
在優化后的代碼中,我們將用于計算數組總和的邏輯提取到了一個名為 calculateSum 的獨立方法中。現在,calculateTotal 和 calculateAverage 方法可以直接調用 calculateSum 來獲取數組的總和,從而避免了代碼重復。
隨著時間的推移,隨著維護代碼的人越來越多,代碼庫容易變得陳舊和混亂。為保證代碼的清晰度和易維護性,就非常有必要對代碼進行重構,使其更易理解、維護和擴展。
在簡化方法的過程中,首先要識別出那些包含復雜嵌套邏輯和承擔過多職責的方法。接著,可以通過以下幾步來簡化它們:
接下來,我們將通過一個 Java 代碼重構示例來具體展示如何簡化方法。
簡化前
public class ShoppingCart { private List<Item> items; // 計算總價 public double calculateTotalCost() { double total = 0; for (Item item : items) { if (item.isDiscounted()) { total += item.getPrice() * 0.8; } else { total += item.getPrice(); } } if (total > 100) { total -= 10; } return total; }}
我們可以通過提取 calculateItemPrice 邏輯到 calculateItemPrice 和 applyDiscount 方法中,并使用三元運算符來簡化條件判斷,使上述示例更為簡潔。
簡化后
public class ShoppingCart { private List<Item> items; // 計算總價 public double calculateTotalCost() { double total = 0; for (Item item : items) { total += calculateItemPrice(item); } total -= applyDiscount(total); return total; } // 計算價格 private double calculateItemPrice(Item item) { return item.isDiscounted() ? item.getPrice() * 0.8 : item.getPrice(); } // 獲取滿減 private double applyDiscount(double total) { return total > 100 ? 10 : 0; }}
圖片來源: Codecademy
紅綠重構,又稱測試驅動開發(TDD),是一種強調先編寫測試再編寫能通過這些測試的代碼的代碼重構技術。該技術是一個循環迭代的過程,每一輪迭代都包括編寫新的測試和足夠的代碼來通過這些測試,最后對代碼進行重構。
這一技術包括以下三個階段:
每完成一個測試用例后,你將進入下一個循環,繼續編寫新的測試用例和對應的代碼,然后再進行代碼重構以實現更好的優化。
可能你已對面向對象編程中的 SOLID 原則有所了解。SOLID 是五個設計原則的首字母縮寫。
單一責任原則是首要原則,該原則強調每個類應僅有一個變化的原因,即一個類只負責一個功能點遵守單一責任原則是確保代碼可維護、可讀、靈活和模塊化的基本方式之一。下面我們將展示一個 OrderProcessor 類的示例,這個類違反了單一責任原則,因為它同時承擔了訂單處理和記錄信息日志兩項職責。
public class OrderProcessor { // 處理訂單 public void processOrder(Order order) { // 訂單驗證 // 處理邏輯 // 日志記錄 Logger logger = new Logger(); logger.log("Order processed: " + order.getId()); }}
為了遵循單一責任原則,我們可以將該類重構為三個類:一個是 OrderProcessor 類,只負責訂單處理;OrderValidator負責訂單校驗,另外一個是 OrderLogger 類,專門負責日志記錄。
public class OrderProcessor { private final OrderValidator orderValidator; public OrderProcessor(OrderValidator orderValidator) { this.orderValidator = orderValidator; } // 處理訂單 public void processOrder(Order order) { // 訂單驗證 if(!orderValidator.validate(order)) { throw new IllegalArgumentException("Order is not valid"); } // 處理邏輯 // ... // 日志記錄 OrderLogger logger = new OrderLogger(); logger.logOrderProcessed(order); }}public class OrderValidator { // 訂單驗證 public boolean validate(Order order) { // 驗證邏輯 // ... return true; }}public class OrderLogger { public void logOrderProcessed(Order order) { Logger logger = new Logger(); logger.log("Order processed: " + order.getId()); }}
代碼重構是一個能夠顯著提升代碼質量的重要步驟,它帶來了我們之前強調的諸多好處。但在進行重構時也需謹慎,特別是在處理龐大的代碼庫或不熟悉的代碼庫時,以避免無意中改變軟件的功能或產生未預見的問題。
為了避免任何潛在問題,您可以參考以下重構 Java 代碼的技巧和最佳實踐:
重構是一項至關重要的技術實踐,它是確保軟件項目長期成功的關鍵。 通過融入我們之前討論的技術到你的開發周期并嚴格遵循最佳實踐,你可以把任何復雜且混亂的代碼庫改造為一個可讀、可維護和可擴展的軟件解決方案。但請注意,Java 代碼重構不是一次性的任務,而是一個可以持續整合到你的開發周期中的過程。
在軟件開發的任何階段都可以進行代碼重構。無論是在添加新功能、修復 bug 還是優化難以理解的代碼片段時,都是進行重構的好時機。定期預留時間來進行重構可以避免技術債務的累積,從而維持代碼庫的高質量。
你可以從識別代碼庫中難以理解、存在重復邏輯或容易產生 bug 的區域開始。尋找具有冗長的方法、復雜條件語句的代碼,并嘗試遵循“單一職責原則”來提高代碼的組織性。
擁有一套完善的自動化測試套件是減少重構過程中引入 bug 的風險的關鍵。在開始重構之前,確保你的代碼具有良好的測試覆蓋率,這將幫助你捕捉任何可能的回歸問題,確保代碼功能的穩定性。
首先,你需要確定目標類并深入理解其行為和依賴關系。然后可以考慮拆分龐大的方法和將方法移動到更適合的類中,同時利用繼承和接口來實現更清晰的結構。此外,重命名變量和方法、重新組織代碼結構和簡化條件語句都可以提高代碼的可讀性。最后,確保對所有更改進行徹底測試,以保證功能的完整性。
劉汪洋,51CTO社區編輯,昵稱:明明如月,一個擁有 5 年開發經驗的某大廠高級 Java 工程師,擁有多個主流技術博客平臺博客專家稱號。
標題:CODE REFACTORING IN JAVA: TIPS, BEST PRACTICES, TECHNIQUES,作者:Digma
本文鏈接:http://www.tebozhan.com/showinfo-26-14127-0.htmlJava中的代碼重構:技巧、優秀實踐與方法
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: Python數據類型:列表的魔法世界
下一篇: Python數據類型:列表的魔法世界