简介
“Change Function Declaration - 更改函数声明 | Change Signature - 更改签名”是一种重构手法,用于修改函数或方法的签名。函数或方法的签名包括函数名称、参数列表(参数的数量、类型和顺序)以及返回值类型。使用该技术可以让函数或方法更符合新的需求,提高代码的可维护性和可扩展性,同时保持其原有功能不变。
针对的症状(代码坏味道)
- 函数或方法参数不合理:当函数或方法的参数列表不符合当前使用场景,例如参数顺序混乱、参数过多或参数类型不合适时,可使用该重构技术。
- 函数或方法命名不清晰:当函数或方法的名称不能准确描述其功能时,可能需要同时修改函数名称和参数列表。
- 函数或方法的返回值不满足需求:当函数或方法的返回值类型或内容需要调整,以更好地满足调用者的需求时。
Change Signature 的详细步骤
- 分析现有签名
- 检查函数或方法的名称:确定函数或方法名称是否准确反映其功能,如果不准确,考虑修改。
- 检查参数列表:分析参数的数量、类型、顺序以及每个参数的使用情况,判断是否需要调整。
- 检查返回值:评估返回值的类型和内容是否符合调用者的期望和使用场景。
- 规划新的签名
- 确定新的函数或方法名称(如果需要):选择一个更具描述性的名称,能清晰表达函数或方法的功能。
- 规划新的参数列表:确定所需的参数,包括数量、类型和顺序,删除不必要的参数,添加需要的参数。
- 确定新的返回值(如果需要):根据调用者的需求,考虑修改返回值的类型或内容。
- 修改函数或方法的声明
- 更新函数或方法的名称(如果有更改):在函数或方法的声明处修改其名称。
- 修改参数列表:根据规划的新参数列表,添加、删除或调整参数。
- 更新返回值类型(如果有更改):在函数或方法的声明处修改返回值类型。
- 调整函数或方法的内部实现
- 根据新的参数使用情况:在函数或方法内部,更新对参数的使用逻辑,确保正确使用新参数。
- 调整返回值逻辑(如果有更改):修改函数或方法内部逻辑,以提供正确的返回值。
- 更新函数或方法的调用处
- 找到所有调用该函数或方法的地方:在整个代码库中找出调用该函数或方法的代码位置。
- 修改调用处的参数:根据新的参数列表,在调用处传递正确的参数。
- 处理返回值(如果有更改):根据新的返回值类型,在调用处正确处理返回值。
- 测试
- 编译代码:确保代码编译通过,没有任何语法错误。
- 运行测试:运行现有的单元测试,确保修改签名的操作没有引入新的错误。如果没有单元测试,编写相应的测试用例进行测试。
- 手动测试:对于涉及用户界面或外部系统交互的函数,进行手动测试,确保功能的正确性。
- 代码审查
- 同行评审:请同事或其他团队成员审查代码,确保修改签名的操作符合代码质量和可维护性标准。
- 文档更新:如果有相关的文档,更新文档中关于该函数或方法的描述,包括新的签名及其作用。
示例
假设我们有一个简单的 Java 类,其中包含一个 printMessage 方法,它接收一个字符串作为参数并打印该消息,但现在我们需要修改其签名。
public class MessagePrinter {
public void printMessage(String message) {
System.out.println(message);
}
}
以下是使用“Change Signature”技术的步骤:
-
分析现有签名:
- 函数名称
printMessage比较合适,但假设我们需要添加一个参数来控制消息的打印次数。 - 当前只有一个参数
message,需要添加一个新的int类型参数表示打印次数。 - 无返回值,无需修改。
- 函数名称
-
规划新的签名:
- 函数名称保持不变。
- 新的参数列表:
(String message, int printCount)。 - 无返回值。
-
修改函数或方法的声明:
-
在
printMessage方法的声明处添加新的参数。public class MessagePrinter { public void printMessage(String message, int printCount) { // 函数内部逻辑将根据新的参数进行修改 } }
-
-
调整函数或方法的内部实现:
-
根据新的参数
printCount,修改函数内部逻辑,多次打印消息。public class MessagePrinter { public void printMessage(String message, int printCount) { for (int i = 0; i < printCount; i++) { System.out.println(message); } } }
-
-
更新函数或方法的调用处:
-
在调用
printMessage的地方添加新的参数。public class Main { public static void main(String[] args) { MessagePrinter printer = new MessagePrinter(); printer.printMessage("Hello, World!", 3); } }
-
-
测试:
- 编译代码,确保代码编译通过。
- 运行测试,确保消息能正确打印指定次数。
- 进行手动测试,检查不同打印次数的情况。
-
代码审查:
- 请同事检查代码,确保代码可读性和可维护性没有下降。
- 更新文档,说明
printMessage方法新增了printCount参数,以及其对方法行为的影响。
练习
基础练习题
-
简单签名修改
-
对于以下 Java 代码,将
calculateSum方法的参数列表修改为接收一个int[]类型的数组,并计算数组元素的总和。public class SumCalculator { public int calculateSum(int a, int b) { return a + b; } }
-
-
修改方法名称和参数
-
对于以下 Java 代码,将
validateUser方法的名称修改为checkUserAge,并将参数修改为接收User对象,根据User对象的年龄进行验证。public class UserValidator { public boolean validateUser(int age) { return age >= 18; } }
-
进阶练习题
-
复杂签名修改
-
在以下 Java 代码中,将
processData方法的签名修改为接收List<Integer>类型的列表作为输入,添加一个String类型的参数operation表示操作类型(如 "sum"、"average"),并根据操作类型修改函数内部逻辑。import java.util.ArrayList; import java.util.List; public class DataProcessor { public int processData(List<Integer> dataList) { int sum = 0; for (int num : dataList) { sum += num; } return sum; } }
-
-
签名修改与返回值调整
- 对于以下 Java 代码,将
calculatePrice方法的签名修改为接收Product对象作为参数,同时修改返回值为double类型,并根据Product的属性计算价格。
public class PriceCalculator { public int calculatePrice(int quantity) { return quantity * 10; } } - 对于以下 Java 代码,将
综合拓展练习题
-
多模块签名修改
-
考虑一个 Java 订单系统,包含
OrderService和ProductService类。在OrderService类的placeOrder方法中修改签名,将参数Product改为Product[]类型的数组,添加一个String类型的参数customerName,并修改返回值为Order对象。在ProductService类的getProduct方法中修改签名,添加一个int类型的参数version,并修改返回值为Product对象。public class OrderService { public void placeOrder(Product product, int quantity) { System.out.println("Placing order for " + quantity + " of " + product.getName()); } } public class Product { private String name; public Product(String name) { this.name = name; } public String getName() { return name; } } public class ProductService { public Product getProduct(int productId) { System.out.println("Getting product with id: " + productId); return new Product("Sample Product"); } }
-
-
代码审查模拟
- 完成上述多模块签名修改的操作后,模拟一份代码审查报告,指出修改签名后的优点和可能存在的潜在问题.## 简介
“Change Function Declaration - 更改函数声明 | Change Signature - 更改签名”是一种重构手法,用于修改函数或方法的签名。函数或方法的签名包括函数名称、参数列表(参数的数量、类型和顺序)以及返回值类型。使用该技术可以让函数或方法更符合新的需求,提高代码的可维护性和可扩展性,同时保持其原有功能不变。
针对的症状(代码坏味道)
- 函数或方法参数不合理:当函数或方法的参数列表不符合当前使用场景,例如参数顺序混乱、参数过多或参数类型不合适时,可使用该重构技术。
- 函数或方法命名不清晰:当函数或方法的名称不能准确描述其功能时,可能需要同时修改函数名称和参数列表。
- 函数或方法的返回值不满足需求:当函数或方法的返回值类型或内容需要调整,以更好地满足调用者的需求时。
Change Signature 的详细步骤
- 分析现有签名
- 检查函数或方法的名称:确定函数或方法名称是否准确反映其功能,如果不准确,考虑修改。
- 检查参数列表:分析参数的数量、类型、顺序以及每个参数的使用情况,判断是否需要调整。
- 检查返回值:评估返回值的类型和内容是否符合调用者的期望和使用场景。
- 规划新的签名
- 确定新的函数或方法名称(如果需要):选择一个更具描述性的名称,能清晰表达函数或方法的功能。
- 规划新的参数列表:确定所需的参数,包括数量、类型和顺序,删除不必要的参数,添加需要的参数。
- 确定新的返回值(如果需要):根据调用者的需求,考虑修改返回值的类型或内容。
- 修改函数或方法的声明
- 更新函数或方法的名称(如果有更改):在函数或方法的声明处修改其名称。
- 修改参数列表:根据规划的新参数列表,添加、删除或调整参数。
- 更新返回值类型(如果有更改):在函数或方法的声明处修改返回值类型。
- 调整函数或方法的内部实现
- 根据新的参数使用情况:在函数或方法内部,更新对参数的使用逻辑,确保正确使用新参数。
- 调整返回值逻辑(如果有更改):修改函数或方法内部逻辑,以提供正确的返回值。
- 更新函数或方法的调用处
- 找到所有调用该函数或方法的地方:在整个代码库中找出调用该函数或方法的代码位置。
- 修改调用处的参数:根据新的参数列表,在调用处传递正确的参数。
- 处理返回值(如果有更改):根据新的返回值类型,在调用处正确处理返回值。
- 测试
- 编译代码:确保代码编译通过,没有任何语法错误。
- 运行测试:运行现有的单元测试,确保修改签名的操作没有引入新的错误。如果没有单元测试,编写相应的测试用例进行测试。
- 手动测试:对于涉及用户界面或外部系统交互的函数,进行手动测试,确保功能的正确性。
- 代码审查
- 同行评审:请同事或其他团队成员审查代码,确保修改签名的操作符合代码质量和可维护性标准。
- 文档更新:如果有相关的文档,更新文档中关于该函数或方法的描述,包括新的签名及其作用。
示例
假设我们有一个简单的 Java 类,其中包含一个 printMessage 方法,它接收一个字符串作为参数并打印该消息,但现在我们需要修改其签名。
public class MessagePrinter {
public void printMessage(String message) {
System.out.println(message);
}
}
以下是使用“Change Signature”技术的步骤:
-
分析现有签名:
- 函数名称
printMessage比较合适,但假设我们需要添加一个参数来控制消息的打印次数。 - 当前只有一个参数
message,需要添加一个新的int类型参数表示打印次数。 - 无返回值,无需修改。
- 函数名称
-
规划新的签名:
- 函数名称保持不变。
- 新的参数列表:
(String message, int printCount)。 - 无返回值。
-
修改函数或方法的声明:
-
在
printMessage方法的声明处添加新的参数。public class MessagePrinter { public void printMessage(String message, int printCount) { // 函数内部逻辑将根据新的参数进行修改 } }
-
-
调整函数或方法的内部实现:
-
根据新的参数
printCount,修改函数内部逻辑,多次打印消息。public class MessagePrinter { public void printMessage(String message, int printCount) { for (int i = 0; i < printCount; i++) { System.out.println(message); } } }
-
-
更新函数或方法的调用处:
-
在调用
printMessage的地方添加新的参数。public class Main { public static void main(String[] args) { MessagePrinter printer = new MessagePrinter(); printer.printMessage("Hello, World!", 3); } }
-
-
测试:
- 编译代码,确保代码编译通过。
- 运行测试,确保消息能正确打印指定次数。
- 进行手动测试,检查不同打印次数的情况。
-
代码审查:
- 请同事检查代码,确保代码可读性和可维护性没有下降。
- 更新文档,说明
printMessage方法新增了printCount参数,以及其对方法行为的影响。
练习
基础练习题
-
简单签名修改
-
对于以下 Java 代码,将
calculateSum方法的参数列表修改为接收一个int[]类型的数组,并计算数组元素的总和。public class SumCalculator { public int calculateSum(int a, int b) { return a + b; } }
-
-
修改方法名称和参数
-
对于以下 Java 代码,将
validateUser方法的名称修改为checkUserAge,并将参数修改为接收User对象,根据User对象的年龄进行验证。public class UserValidator { public boolean validateUser(int age) { return age >= 18; } }
-
进阶练习题
-
复杂签名修改
-
在以下 Java 代码中,将
processData方法的签名修改为接收List<Integer>类型的列表作为输入,添加一个String类型的参数operation表示操作类型(如 "sum"、"average"),并根据操作类型修改函数内部逻辑。import java.util.ArrayList; import java.util.List; public class DataProcessor { public int processData(List<Integer> dataList) { int sum = 0; for (int num : dataList) { sum += num; } return sum; } }
-
-
签名修改与返回值调整
- 对于以下 Java 代码,将
calculatePrice方法的签名修改为接收Product对象作为参数,同时修改返回值为double类型,并根据Product的属性计算价格。
public class PriceCalculator { public int calculatePrice(int quantity) { return quantity * 10; } } - 对于以下 Java 代码,将
综合拓展练习题
-
多模块签名修改
-
考虑一个 Java 订单系统,包含
OrderService和ProductService类。在OrderService类的placeOrder方法中修改签名,将参数Product改为Product[]类型的数组,添加一个String类型的参数customerName,并修改返回值为Order对象。在ProductService类的getProduct方法中修改签名,添加一个int类型的参数version,并修改返回值为Product对象。public class OrderService { public void placeOrder(Product product, int quantity) { System.out.println("Placing order for " + quantity + " of " + product.getName()); } } public class Product { private String name; public Product(String name) { this.name = name; } public String getName() { return name; } } public class ProductService { public Product getProduct(int productId) { System.out.println("Getting product with id: " + productId); return new Product("Sample Product"); } }
-
-
代码审查模拟
- 完成上述多模块签名修改的操作后,模拟一份代码审查报告,指出修改签名后的优点和可能存在的潜在问题.