简介
“移动字段”(Move Field)是一种重构手法,通过将一个字段从一个类移动到另一个类,从而更好地组织代码结构,使类的职责更加清晰。这种方法特别适用于当一个字段被另一个类频繁使用时,或者当一个字段与当前类的职责不匹配时。以下是进行“移动字段”重构的详细步骤:
针对的症状(代码坏味道)
- 字段被其他类频繁使用(Field Used by Another Class)
- 字段与当前类的职责不匹配(Field Doesn't Belong to Current Class)
移动字段(Move Field)的详细步骤
- 识别需要移动的字段
- 寻找被其他类频繁使用的字段。
- 确定这些字段是否更适合放在另一个类中。
- 创建目标类中的字段
- 在目标类中创建相同的字段。
- 确保目标类有适当的访问方法(getter 和 setter)。
- 更新原始类中的字段引用
- 将原始类中对字段的引用替换为对目标类中字段的引用。
- 确保所有相关的地方都更新为使用目标类中的字段。
- 测试
- 编译代码:确保代码编译通过,没有任何语法错误。
- 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
- 手动测试:如果有必要,进行手动测试以验证功能的正确性。
- 代码审查
- 同行评审:让同事或其他团队成员审查你的更改,确保代码质量和可维护性没有下降。
- 文档更新:如果项目有维护文档的习惯,记得更新相关文档,说明移动字段的影响。
示例
假设有一个类 Order,其中包含一个字段 customerName,但这个字段被 Customer 类频繁使用,我们希望对其进行“移动字段”的重构:
public class Order {
private String customerName;
private double totalAmount;
public Order(String customerName, double totalAmount) {
this.customerName = customerName;
this.totalAmount = totalAmount;
}
public String getCustomerName() {
return customerName;
}
public double getTotalAmount() {
return totalAmount;
}
}
public class Customer {
private String name;
public Customer(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
步骤如下:
-
识别需要移动的字段:
- 字段
customerName被Customer类频繁使用。
- 字段
-
创建目标类中的字段:
-
在
Customer类中创建字段name:public class Customer { private String name; public Customer(String name) { this.name = name; } public String getName() { return name; } }
-
-
更新原始类中的字段引用:
-
将
Order类中对customerName的引用替换为对Customer类中name的引用:public class Order { private Customer customer; private double totalAmount; public Order(Customer customer, double totalAmount) { this.customer = customer; this.totalAmount = totalAmount; } public String getCustomerName() { return customer.getName(); } public double getTotalAmount() { return totalAmount; } }
-
-
测试:
- 编译代码:确保代码编译通过,没有任何语法错误。
- 运行测试:运行所有相关的单元测试,确保重构操作没有引入新的错误。
-
代码审查:
- 让同事审查代码,确保没有引入新的问题。
练习
基础练习题
- 移动简单字段
-
给定以下 Java 代码,
Employee类中的departmentName字段被Department类频繁使用。请将该字段移动到Department类中。public class Employee { private String name; private String departmentName; public Employee(String name, String departmentName) { this.name = name; this.departmentName = departmentName; } public String getName() { return name; } public String getDepartmentName() { return departmentName; } } public class Department { private String name; public Department(String name) { this.name = name; } public String getName() { return name; } }
-
- 移动复杂字段
-
下面的 Java 代码中有两个类
Product和Category,Product类中的categoryName字段被Category类频繁使用。请将该字段移动到Category类中。public class Product { private String name; private String categoryName; public Product(String name, String categoryName) { this.name = name; this.categoryName = categoryName; } public String getName() { return name; } public String getCategoryName() { return categoryName; } } public class Category { private String name; public Category(String name) { this.name = name; } public String getName() { return name; } }
-
进阶练习题
- 移动复杂逻辑字段
-
在这段 Java 代码中,
Order类中的shippingCost字段被ShippingInfo类频繁使用。请将该字段移动到ShippingInfo类中。public class Order { private double totalAmount; private double shippingCost; public Order(double totalAmount, double shippingCost) { this.totalAmount = totalAmount; this.shippingCost = shippingCost; } public double getTotalAmount() { return totalAmount; } public double getShippingCost() { return shippingCost; } } public class ShippingInfo { private double baseShippingCost; private double discountRate; public ShippingInfo(double baseShippingCost, double discountRate) { this.baseShippingCost = baseShippingCost; this.discountRate = discountRate; } public double getBaseShippingCost() { return baseShippingCost; } public double getDiscountRate() { return discountRate; } }
-
- 移动方法与返回值字段
-
给定以下 Java 代码,
DataProcessor类中的dataArray字段被DataTransformer类频繁使用。请将该字段移动到DataTransformer类中。import java.util.ArrayList; import java.util.List; public class DataProcessor { private int[] dataArray; public DataProcessor(int[] dataArray) { this.dataArray = dataArray; } public int[] getDataArray() { return dataArray; } public int processData() { List<Integer> processedData = new ArrayList<>(); for (int num : dataArray) { num = num * 2; if (num > 10) { num = num - 5; } processedData.add(num); } int sum = 0; for (int num : processedData) { sum += num; } return sum; } } public class DataTransformer { private int[] dataArray; public DataTransformer(int[] dataArray) { this.dataArray = dataArray; } public int[] getDataArray() { return dataArray; } }
-
综合拓展练习题
- 多模块移动字段与代码审查模拟
-
考虑一个简单的 Java 电商系统,有
Product类、Cart类和Order类。Cart类中的discountRate字段被Order类频繁使用,同时Order类中的shippingCost字段被ShippingInfo类频繁使用。 -
请对这些字段进行 “移动字段” 重构,将字段移动到更适合的类中。
-
假设你完成了重构,请模拟一份简单的代码审查报告,指出重构后的优点和可能存在的潜在问题。
class Product { private double price; public Product(double price) { this.price = price; } public double getPrice() { return price; } } class Cart { private Product[] products; private double discountRate; public Cart(Product[] products, double discountRate) { this.products = products; this.discountRate = discountRate; } public double calculateCartTotal() { double total = 0; for (Product product : products) { total += product.getPrice(); } return total - (total * discountRate); } public void applyCartDiscount() { if (products.length > 3) { discountRate += 0.05; } if (calculateCartTotal() > 100) { discountRate += 0.1; } } } class Order { private Product[] products; private double shippingCost; public Order(Product[] products, double shippingCost) { this.products = products; this.shippingCost = shippingCost; } public double calculateOrderTotal() { double total = 0; for (Product product : products) { total += product.getPrice(); } return total + shippingCost; } } class ShippingInfo { private double baseShippingCost; private double discountRate; public ShippingInfo(double baseShippingCost, double discountRate) { this.baseShippingCost = baseShippingCost; this.discountRate = discountRate; } public double getBaseShippingCost() { return baseShippingCost; } public double getDiscountRate() { return discountRate; } }
-