Java代码重构之提取方法

Java代码重构之提取方法是指将一部分代码逻辑抽取出来作为一个独立的方法,以提高代码的可读性、可维护性和重用性。下面是一个例子来说明什么情况下需要进行方法提取重构,以及重构后的代码示例。 假设我们有一个计算员工年度薪水的程序,其中包含以下代码片段: ```java double calculateYearlySalary(String name, double monthlySalary) { double yearlySalary; if (monthlySalary < 0) { throw new IllegalArgumentException("Monthly salary cannot be negative."); } if (name == null || name.isEmpty()) { throw new IllegalArgumentException("Name cannot be null or empty."); } // 假设还有其他的逻辑 yearlySalary = monthlySalary * 12; return yearlySalary; } ``` 上述代码在计算年度薪水之前进行了参数的合法性检查,并且还有一些其他的逻辑,如计算税金等等。然而,我们发现参数检查的逻辑(if语句)占据了大量的代码行数,并且在多处重复出现,导致代码重复和冗长。这个时候就可以考虑进行方法提取来优化代码。 我们可以将参数检查的逻辑提取为一个独立的方法,如下所示: ```java void validateInputs(String name, double monthlySalary) { if (monthlySalary < 0) { throw new IllegalArgumentException("Monthly salary cannot be negative."); } if (name == null || name.isEmpty()) { throw new IllegalArgumentException("Name cannot be null or empty."); } } ``` 然后,在原方法调用前先调用新提取出的方法,示例如下: ```java double calculateYearlySalary(String name, double monthlySalary) { validateInputs(name, monthlySalary); double yearlySalary; // 假设还有其他的逻辑 yearlySalary = monthlySalary * 12; return yearlySalary; } ``` 通过提取方法,我们使得原方法更加简洁明了,而且将参数检查的逻辑抽取到一个独立的方法中,可以提高代码的可读性和可维护性。同时,提取出的方法也可以在其他地方进行重用,避免了代码的重复编写。 总结:方法提取重构可以在需要复用一段相同或类似的代码逻辑时使用,通过提取出一个独立的方法来实现代码的重用和逻辑的整理,提高代码的可读性、可维护性和重用性。

Java代码重构之抽象类和接口

在Java中,抽象类和接口是用来实现代码重构的强大工具。下面使用一个简单的例子来说明什么情况下需要进行这样的重构以及重构后的代码。 假设有一个汽车制造公司,该公司生产各种类型的汽车。最初的代码如下: ```java public class Car { private String brand; private String model; private int year; public Car(String brand, String model, int year) { this.brand = brand; this.model = model; this.year = year; } public void drive() { System.out.println("Driving " + brand + " " + model); } } public class Suv extends Car { private boolean offRoad; public Suv(String brand, String model, int year, boolean offRoad) { super(brand, model, year); this.offRoad = offRoad; } public void drive() { System.out.println("Driving " + brand + " " + model + " off-road"); } } public class Sedan extends Car { public Sedan(String brand, String model, int year) { super(brand, model, year); } } public class Main { public static void main(String[] args) { Car car1 = new Car("Toyota", "Camry", 2022); car1.drive(); Suv suv1 = new Suv("Ford", "Explorer", 2022, true); suv1.drive(); Sedan sedan1 = new Sedan("Honda", "Accord", 2022); sedan1.drive(); } } ``` 在上述代码中,汽车类型的特征和行为都放在了`Car`类中,而`Suv`类和`Sedan`类仅继承了`Car`类,并没有增加额外的特征或行为。 在这种情况下,可以使用抽象类和接口对代码进行重构。 首先,创建一个抽象类`Vehicle`,其中包含了所有车辆共有的特征和行为。抽象类可以定义抽象方法(没有具体实现)和具体方法(有具体实现),抽象类不能直接实例化,只能被继承。 ```java public abstract class Vehicle { protected String brand; protected String model; protected int year; public Vehicle(String brand, String model, int year) { this.brand = brand; this.model = model; this.year = year; } public abstract void drive(); } ``` 接下来,将`Car`类改为继承自`Vehicle`类,`Suv`和`Sedan`类也同样改为继承自`Vehicle`类。 ```java public class Car extends Vehicle { public Car(String brand, String model, int year) { super(brand, model, year); } @Override public void drive() { System.out.println("Driving " + brand + " " + model); } } public class Suv extends Vehicle { private boolean offRoad; public Suv(String brand, String model, int year, boolean offRoad) { super(brand, model, year); this.offRoad = offRoad; } @Override public void drive() { System.out.println("Driving " + brand + " " + model + " off-road"); } } public class Sedan extends Vehicle { public Sedan(String brand, String model, int year) { super(brand, model, year); } @Override public void drive() { System.out.println("Driving " + brand + " " + model); } } ``` 最后,修改`Main`类中的代码来使用重构后的类。 ```java public class Main { public static void main(String[] args) { Vehicle car1 = new Car("Toyota", "Camry", 2022); car1.drive(); Vehicle suv1 = new Suv("Ford", "Explorer", 2022, true); suv1.drive(); Vehicle sedan1 = new Sedan("Honda", "Accord", 2022); sedan1.drive(); } } ``` 重构后的代码将共有的特征和行为提取到了抽象类`Vehicle`中,并通过继承来实现不同车辆类型的特定行为。这样做的好处是代码更加清晰、可维护性更高,当需要添加新的车辆类型时,只需要创建一个新的子类继承自`Vehicle`类并实现特定的行为即可。

Java代码重构之修改变量名和方法名

需要进行变量名和方法名的重构的情况有以下几种: 1. 变量名和方法名不符合命名规范:命名规范可根据公司的编码规范来确定,通常使用驼峰命名法。如果变量名和方法名使用了全大写或全小写、使用了特殊字符或缩写等,就需要进行重构以符合命名规范。 重构前的代码: ```java String UFN; // 错误的命名规范,使用了全大写 public void setd() { // 错误的命名规范,使用了缩写 \t// code logic } ``` 重构后的代码: ```java String userName; // 正确的命名规范 public void setDate() { // 正确的命名规范 \t// code logic } ``` 2. 变量名和方法名不具有描述性:变量名和方法名应能清晰地表达其用途和意义,便于理解代码的功能和含义。如果变量名和方法名太过简单或过于抽象,会给他人阅读和维护代码带来困难。 重构前的代码: ```java int a; // 缺乏描述性的变量名 public void func(String p) { // 缺乏描述性的方法名 \t// code logic } ``` 重构后的代码: ```java int userAge; // 描述性的变量名 public void deleteUser(String userId) { // 描述性的方法名 \t// code logic } ``` 3. 变量名和方法名重名或容易产生混淆:如果在同一个作用域内有重名的变量或方法,或者命名过于相似容易产生混淆,就需要进行重构以避免命名冲突。 重构前的代码: ```java int count; public void getCount() { \t// code logic } ``` 重构后的代码: ```java int totalCount; // 重命名以避免和方法名重名 public void fetchCount() { // 重命名以避免和变量名重名 \t// code logic } ``` 通过修改变量名和方法名,可以增加代码的可读性和可维护性,使代码更容易被理解和使用。

Java代码重构之拆分类

拆分类是一种重构技术,它的目的是将一个大而复杂的类拆分为多个小而简单的类,每个类都负责某个特定的责任或功能。这样做可以提高代码的可读性、可维护性和可扩展性。 下面是一个需要使用拆分类重构的示例代码: ```java public class Order { private String orderId; private String customerName; private String customerEmail; private List<Product> products; private double total; // constructor, getters, setters, etc. public void processOrder() { // 处理订单逻辑 } public void sendConfirmationEmail() { // 发送确认邮件逻辑 } public void calculateTotal() { // 计算订单总额逻辑 } } ``` 在这个示例代码中,Order类承担了太多的责任,它既负责订单的处理逻辑,又负责发送确认邮件和计算订单总额。这导致Order类变得庞大而复杂,不符合单一职责原则(SRP)。 为了改善这个问题,可以将Order类拆分为三个小类: ```java public class Order { private String orderId; private String customerName; private String customerEmail; private List<Product> products; // constructor, getters, setters, etc. } public class OrderProcessor { public void processOrder(Order order) { // 处理订单逻辑 } } public class OrderMailer { public void sendConfirmationEmail(Order order) { // 发送确认邮件逻辑 } } public class OrderCalculator { public double calculateTotal(Order order) { // 计算订单总额逻辑 } } ``` 通过拆分类,每个类都只负责特定的功能,代码变得更加清晰和可维护。Order类只保留订单的属性,而具体的处理、发送邮件和计算总额逻辑都被移到了相应的拆分类中。 拆分类重构后的代码可以更容易地进行功能的修改和扩展。例如,如果需要更改订单处理逻辑或发送确认邮件逻辑,只需要修改相应的拆分类,而不影响其他功能。同时,也提高了代码的可测试性,因为每个类的功能单一,可以更方便地进行单元测试。 总之,拆分类是一种有助于提高代码可读性、可维护性和可扩展性的重构技术,适用于类变得庞大复杂,承担了过多责任的情况。

Java代码重构之合并类

在Java中,合并类是一种重构技术,它将相关联的类合并为一个更大的类,通常用于消除过度细化或重复工作的情况。以下是一个示例代码,说明什么情况下需要进行合并类重构以及重构后的代码: ```java // 合并前的代码 class User { private String firstName; private String lastName; public User(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } } class Order { private String orderNumber; private double amount; private User user; public Order(String orderNumber, double amount, User user) { this.orderNumber = orderNumber; this.amount = amount; this.user = user; } public String getOrderNumber() { return orderNumber; } public double getAmount() { return amount; } public User getUser() { return user; } } public class Main { public static void main(String[] args) { User user = new User("John", "Doe"); Order order = new Order("12345", 100.00, user); System.out.println("Order " + order.getOrderNumber() + " belongs to " + order.getUser().getFirstName() + " " + order.getUser().getLastName()); } } ``` 在上述代码中,`User`和`Order`类具有紧密的关联关系,`Order`类依赖于`User`类来提供与用户相关的信息。然而,这种关联关系可能导致重复代码和逻辑分散。 通过合并这两个类,我们可以将`getFirstName()`和`getLastName()`方法添加到`Order`类中,并直接访问用户信息,而无需通过`User`对象。下面是合并类重构后的代码: ```java // 合并后的代码 class Order { private String orderNumber; private double amount; private String firstName; private String lastName; public Order(String orderNumber, double amount, String firstName, String lastName) { this.orderNumber = orderNumber; this.amount = amount; this.firstName = firstName; this.lastName = lastName; } public String getOrderNumber() { return orderNumber; } public double getAmount() { return amount; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } } public class Main { public static void main(String[] args) { Order order = new Order("12345", 100.00, "John", "Doe"); System.out.println("Order " + order.getOrderNumber() + " belongs to " + order.getFirstName() + " " + order.getLastName()); } } ``` 在重构后的代码中,`Order`类包含所有与用户相关的信息,这样可以提高代码的可读性和维护性,并消除了对`User`类的依赖。 需要合并类的情况通常包括两个类之间有紧密的关联关系,但这种关联关系并不需要保持独立,或者一个类需要使用另一个类的成员而不希望通过对象访问,从而增加了代码的复杂性。 要注意,合并类并不是无条件适用的重构技术,必须根据具体情况进行评估。在某些场景下,保持类的独立性和低耦合可能更为重要,而合并类可能会导致代码变得混乱或难以维护。因此,在进行任何重构之前,应仔细评估并权衡各种方案的优缺点。

Java代码重构之简化逻辑表达式

重构逻辑表达式可以使代码更简洁、可读性更好,常见的情况有以下几种: 1. 多个条件判断:当代码中出现多个条件判断语句时,可以通过合并或简化条件表达式来提高代码的可读性。例如,原始代码如下: ``` if (a > 10 && b < 5 && c == 0 && d != 10) { // do something } ``` 重构后的代码如下: ``` if (a > 10 && b < 5 && c == 0 && d != 10) { // do something } ``` 通过重构后的代码,可以更清晰地看到所有条件,并且代码更加简洁。 2. 嵌套的逻辑表达式:当逻辑表达式中存在嵌套的情况时,可以通过提取方法或使用逻辑运算符来简化代码。例如,原始代码如下: ```java if ((a > 5 && b < 10) || (c == 0 && d != 5)) { // do something } ``` 重构后的代码如下: ```java boolean condition1 = a > 5 && b < 10; boolean condition2 = c == 0 && d != 5; if (condition1 || condition2) { // do something } ``` 通过重构后的代码,可以通过变量名更好地表达逻辑含义,使代码更易读。 3. 重复的逻辑判断:当代码中存在重复的逻辑判断时,可以通过提取方法或使用逻辑运算符来简化代码。例如,原始代码如下: ```java if (a > 10 || b > 5) { // do something } if (a > 10 || b > 5) { // do something else } ``` 重构后的代码如下: ```java boolean condition = a > 10 || b > 5; if (condition) { // do something } if (condition) { // do something else } ``` 通过重构后的代码,可以避免重复的逻辑判断,提高代码的可维护性。 重构逻辑表达式能够使代码更简洁、可读性更好,提高代码的可维护性和可理解性。

Java代码重构之重构条件语句

条件语句的重构可以在以下情况下进行: 1. 重复的条件逻辑:如果在代码中存在多个地方使用相同的条件语句,可以考虑将其提取为一个方法或函数。这样可以减少代码的重复性,并提高代码的可读性和可维护性。 ```java // 重构前 if (condition) { // do something // ... } // 重构后 if (hasConditionTrue()) { // do something // ... } // 移动到其他方法或类中 public boolean hasConditionTrue() { return condition; } ``` 2. 复杂的条件判断:如果条件语句过于复杂,难以理解和测试,可以考虑将其拆分为多个独立的条件或方法。这样可以使代码更清晰、可读性更好,并且可以针对不同条件编写更容易测试的单元测试。 ```java // 重构前 if (condition1 && (condition2 || condition3) && !condition4) { // do something // ... } // 重构后 if (isConditionTrue()) { // do something // ... } // 移动到其他方法或类中 public boolean isConditionTrue() { return condition1 && (condition2 || condition3) && !condition4; } ``` 3. 大量的嵌套条件:如果条件语句过多嵌套,导致代码结构混乱、可读性差以及出错的可能性增加,可以考虑对其进行简化。将复杂的条件逻辑拆分为多个独立的条件判断,使用早返回和提前判断等技巧,使代码的逻辑更加直观和简洁。 ```java // 重构前 if (condition1) { if (condition2) { if (condition3) { // do something // ... } } } // 重构后 if (!condition1) { return; } if (!condition2) { return; } if (!condition3) { return; } // do something // ... ``` 以上几个例子都是针对条件语句的重构,目的是为了提高代码的可读性、可维护性和可测试性。通过将重复逻辑提取为方法或函数,拆分复杂的条件判断以及简化嵌套条件,可以使代码更简洁、更易于理解和修改。

Java代码重构之代码重用

重用代码是指通过将现有的代码段抽象出来,形成可以在多个地方使用的独立功能单元,以实现代码的复用。以下是一个示例代码,解释了何时需要进行代码重构以及重构后的代码。 示例代码: ```java public class Calculator { public int add(int a, int b) { return a + b; } public int subtract(int a, int b) { return a - b; } public int multiply(int a, int b) { return a * b; } public int divide(int a, int b) { if(b == 0) { throw new IllegalArgumentException("除数不能为0"); } return a / b; } } public class Main { public static void main(String[] args) { Calculator calculator = new Calculator(); int result1 = calculator.add(5, 3); System.out.println(result1); // 输出:8 int result2 = calculator.subtract(5, 3); System.out.println(result2); // 输出:2 int result3 = calculator.multiply(5, 3); System.out.println(result3); // 输出:15 int result4 = calculator.divide(10, 2); System.out.println(result4); // 输出:5 } } ``` 在上述示例代码中,Calculator类实现了基本的数学运算功能,然后在Main类中通过创建Calculator对象,调用其不同的方法来进行不同的数学运算。 在当前的实现中,每次需要进行数学运算时都需要创建一个新的Calculator对象,这样就造成了代码的重复。如果我们需要在多个地方进行数学运算,就需要在每个地方都进行创建对象和调用方法的重复工作。 为了解决这个问题,我们可以将Calculator对象创建和方法调用的代码放到一个公共方法中,并将Calculator对象作为参数传递进去,这样就可以实现代码的重用。 重构后的代码: ```java public class Calculator { public int add(int a, int b) { return a + b; } public int subtract(int a, int b) { return a - b; } public int multiply(int a, int b) { return a * b; } public int divide(int a, int b) { if(b == 0) { throw new IllegalArgumentException("除数不能为0"); } return a / b; } } public class MathUtil { public static int calculate(Calculator calculator, int a, int b) { return calculator.add(a, b); } public static void main(String[] args) { Calculator calculator = new Calculator(); int result1 = MathUtil.calculate(calculator, 5, 3); System.out.println(result1); // 输出:8 int result2 = MathUtil.calculate(calculator, 5, 3); System.out.println(result2); // 输出:2 int result3 = MathUtil.calculate(calculator, 5, 3); System.out.println(result3); // 输出:15 int result4 = MathUtil.calculate(calculator, 10, 2); System.out.println(result4); // 输出:5 } } ``` 在重构后的代码中,我们创建了一个MathUtil类,其中的calculate方法接收一个Calculator对象和两个参数,然后调用Calculator对象的add方法进行数学运算。这样,我们就可以在不同的地方直接调用MathUtil类的calculate方法来进行数学运算,避免了重复创建对象和调用方法的工作。