译者 | 刘汪洋
审校 | 重楼
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.28at.com/showinfo-26-14127-0.htmlJava中的代码重构:技巧、优秀实践与方法
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: Python数据类型:列表的魔法世界
下一篇: Python数据类型:列表的魔法世界