重构手法——对象结构优化类 | 集成体系重构 | 将函数合并到转换中

81 阅读6分钟

简介

“将函数合并到转换中”(Combine Functions into Transform)是一种重构手法,旨在将多个相关的函数组合成一个转换函数,以简化代码结构,提高代码的可读性和可维护性。这种重构手法特别适用于那些对数据进行多次处理或转换的场景,将这些分散的处理步骤整合在一起,形成一个连贯的转换流程,使代码更具逻辑性和一致性。

针对的症状(代码坏味道)

  • 分散的转换函数:存在多个函数对数据进行连续的处理或转换操作,但这些函数分散在不同的地方,导致代码逻辑不够连贯。
  • 数据处理流程复杂:当数据在多个函数之间传递,并且每个函数都执行一部分转换操作时,代码的复杂性会增加,难以追踪数据的完整转换过程。
  • 难以维护:由于转换操作分散在不同的函数中,修改或扩展数据处理逻辑变得困难,可能需要同时修改多个函数,增加出错的风险。

将函数合并到转换中(Combine Functions into Transform)的详细步骤

  1. 识别相关的转换函数
    • 查找对相同数据进行处理或转换的函数:分析代码库,找出那些操作同一类型数据且执行一系列相关转换操作的函数。
    • 确认转换的逻辑顺序:确定这些函数在处理数据时的逻辑顺序,以便将它们按照正确的顺序组合到一个转换函数中。
  2. 创建新的转换函数
    • 选择合适的函数名:为新的转换函数取一个能清晰反映其对数据进行何种转换的名称。
    • 确定输入参数:明确新函数所需的输入参数,通常是要转换的数据及可能的配置信息。
    • 考虑返回值:根据最终的转换结果,确定新函数的返回值类型,可能是转换后的数据,也可能是包含转换后数据的对象。
  3. 合并函数逻辑
    • 将原函数中的逻辑按顺序复制到新的转换函数中:将识别出的相关函数的代码逻辑依次复制到新函数中,确保逻辑顺序正确。
    • 调整代码:根据新函数的输入参数和返回值,调整合并后的代码,消除冗余或不必要的中间变量。
    • 处理异常和边界情况:在合并过程中,注意原函数中的异常处理和边界情况,确保新函数也能正确处理。
  4. 替换原始调用
    • 找到原函数的调用点:在代码中找出调用原函数的位置。
    • 调用新的转换函数:使用新的转换函数替换原函数的调用,确保输入参数正确传递,接收正确的返回结果。
    • 验证功能:确保替换后的代码在功能上与原代码等效。
  5. 测试
    • 编译代码:确保代码编译通过,没有语法错误。
    • 运行测试:执行原有的单元测试和集成测试,确保重构未引入新的错误。
    • 手动测试:根据需要进行手动测试,尤其是对于涉及复杂数据转换的部分,确保转换结果符合预期。
  6. 代码审查
    • 同行评审:请同事或团队成员审查重构后的代码,确保代码的质量和可维护性得到提升。
    • 文档更新:如果有文档记录代码功能,更新相应文档,说明重构的变化和影响。

示例

假设以下 Java 代码,有多个函数对一个字符串进行不同的转换操作:

class StringTransformer {
   public static String removeSpaces(String input) {
      return input.replaceAll(" ", "");
   }

   public static String toUpperCase(String input) {
      return input.toUpperCase();
   }

   public static String addPrefix(String input, String prefix) {
      return prefix + input;
   }
}

步骤如下:

  1. 识别相关的转换函数:
    • removeSpacestoUpperCaseaddPrefix 都对字符串进行转换操作。
  2. 创建新的转换函数:
    • 命名为 transformString,将上述函数的逻辑合并。

        class StringTransformer {
           public static String transformString(String input, String prefix) {
        // 移除空格
              String result = input.replaceAll(" ", "");
        // 转换为大写
              result = result.toUpperCase();
        // 添加前缀
              result = prefix + result;
              return result;
           }
        }
      
  3. 合并函数逻辑:
    • removeSpacestoUpperCaseaddPrefix 的逻辑按顺序放入 transformString 中。
    • 调整代码,使用 result 变量存储中间结果。
  4. 替换原始调用:
    • 原调用代码:

        String transformed = StringTransformer.removeSpaces("hello world");
        transformed = StringTransformer.toUpperCase(transformed);
        transformed = StringTransformer.addPrefix(transformed, "PREFIX_");
      
    • 替换为:

        String transformed = StringTransformer.transformString("hello world", "PREFIX_");
      
  5. 测试:
    • 编译代码,确保编译通过。
    • 运行测试:检查现有测试是否通过,可能需要添加新测试来覆盖新函数。
    • 手动测试:验证 transformString 函数是否正确转换字符串。
  6. 代码审查:
    • 请同事检查代码,确保逻辑清晰,没有引入新问题。

练习

基础练习题

  1. 合并数字转换函数
    • 以下 Java 代码中有几个函数对数字进行不同的转换操作,请将它们合并到一个新的转换函数中。

        class NumberTransformer {
           public static int square(int num) {
              return num * num;
           }
      
           public static int addOne(int num) {
              return num + 1;
           }
      
           public static int multiplyByTwo(int num) {
              return num * 2;
           }
        }
      
  2. 整合字符串数组处理函数
    • 下面的代码中,有多个函数对字符串数组进行处理,请将它们合并到一个新的转换函数中。

        class StringArrayHandler {
           public static String[] removeEmpty(String[] array) {
              List<String> resultList = new ArrayList<>();
              for (String str : array) {
                 if (!str.isEmpty()) {
                    resultList.add(str);
                 }
              }
              return resultList.toArray(new String[0]);
           }
      
           public static String[] toUpperCaseArray(String[] array) {
              String[] result = new String[array.length];
              for (int i = 0; i < array.length; i++) {
                 result[i] = array[i].toUpperCase();
              }
              return result;
           }
        }
      

进阶练习题

  1. 合并复杂数据转换函数
    • 在这段 Java 代码中,有几个函数对自定义对象进行不同的转换操作,请将它们合并到一个新的转换函数中,并正确处理参数和异常。

        class DataTransformer {
           public static CustomData adjustData(CustomData data) {
              data.setValue(data.getValue() + 10);
              return data;
           }
      
           public static CustomData validateData(CustomData data) {
              if (data.getValue() < 0) {
                 throw new IllegalArgumentException("Invalid data value");
              }
              return data;
           }
      
           public static CustomData processData(CustomData data) {
              data.setName(data.getName().toUpperCase());
              return data;
           }
        }
      
  2. 组合对象列表转换函数
    • 以下 Java 代码包含对对象列表进行不同转换操作的函数,请将它们合并到一个新的转换函数中,确保返回值处理正确。

        import java.util.ArrayList;
        import java.util.List;
      
        class ObjectListHandler {
           public static List<CustomObject> filterList(List<CustomObject> list) {
              List<CustomObject> result = new ArrayList<>();
              for (CustomObject obj : list) {
                 if (obj.isValid()) {
                    result.add(obj);
                 }
              }
              return result;
           }
      
         public static List<CustomObject> transformList(List<CustomObject> list) {
            List<CustomObject> result = new ArrayList<>();
            for (CustomObject obj : list) {
               CustomObject newObj = new CustomObject(obj.getValue() * 2);
               result.add(newObj);
            }
            return result;
         }
        }
      

综合拓展练习题

  1. 多模块转换函数合并与优化
    • 考虑一个简单的文件处理系统,包含 FileReader 类、FileParser 类和 DataProcessor 类,它们都有对文件数据进行不同处理的函数。

    • 将这些类中的相关转换函数合并到一个新的 FileDataTransformer 类的转换函数中。

    • 模拟一份代码审查报告,指出重构后的优点和可能存在的潜在问题。

        class FileReader {
           public static String readFile(String filePath) {
        // 假设这里有读取文件的逻辑
              return "File content";
           }
        }
      
        class FileParser {
           public static List<String> parseContent(String content) {
        // 假设这里有解析文件内容的逻辑
              return new ArrayList<>();
           }
        }
      
        class DataProcessor {
           public static void processData(List<String> data) {
        // 假设这里有处理数据的逻辑
           }
        }