java - 如何消除for循环中的重复代码?

标签 java dry

我在同一个类中实现了两个成员函数:

  private static void getRequiredTag(Context context) throws IOException
  {
    //repeated begin
    for (Record record : context.getContext().readCacheTable("subscribe")) {
      String traceId = record.get("trace_id").toString();
      if (traceSet.contains(traceId) == false)
        continue;
      String tagId = record.get("tag_id").toString();
      try {
        Integer.parseInt(tagId);
      } catch (NumberFormatException e) {
        context.getCounter("Error", "tag_id not a number").increment(1);
        continue;
      }
      //repeated end
      tagSet.add(tagId);
    }
  }

  private static void addTagToTraceId(Context context) throws IOException
  {
    //repeated begin
    for (Record record : context.getContext().readCacheTable("subscribe")) {
      String traceId = record.get("trace_id").toString();
      if (traceSet.contains(traceId) == false)
        continue;
      String tagId = record.get("tag_id").toString();
      try {
        Integer.parseInt(tagId);
      } catch (NumberFormatException e) {
        context.getCounter("Error", "tag_id not a number").increment(1);
        continue;
      }
      //repeated end
      Vector<String> ret = traceListMap.get(tagId);
      if (ret == null) {
        ret = new Vector<String>();
      }
      ret.add(traceId);
      traceListMap.put(tagId, ret);
    }    
  }

我将在另外两个成员函数中调用这两个成员函数(所以我不能将它们合并到一个函数中):

private static void A()
{
  getRequiredTag()
}
private static void B()
{
  getRequiredTag()
  addTagToTraceId()
}

tagSetjava.util.SettraceListMapjava.util.Map

我知道DRY原则,我很想消除重复代码,所以我来了这段代码:

  private static void getTraceIdAndTagIdFromRecord(Record record, String traceId, String tagId) throws IOException
  {
    traceId = record.get("trace_id").toString();
    tagId = record.get("tag_id").toString();
  }

  private static boolean checkTagIdIsNumber(String tagId)
  {
    try {
      Integer.parseInt(tagId);
    } catch (NumberFormatException e) {
      return false;
    }
    return true;
  }

  private static void getRequiredTag(Context context) throws IOException
  {
    String traceId = null, tagId = null;
    for (Record record : context.getContext().readCacheTable("subscribe")) {
      getTraceIdAndTagIdFromRecord(record, traceId, tagId);
      if (traceSet.contains(traceId) == false)
        continue;
      if (!checkTagIdIsNumber(tagId))
      {
        context.getCounter("Error", "tag_id not a number").increment(1);
        continue;
      }
      tagSet.add(tagId);
    }
  }

  private static void addTagToTraceId(Context context) throws IOException
  {
    String traceId = null, tagId = null;
    for (Record record : context.getContext().readCacheTable("subscribe")) {
      getTraceIdAndTagIdFromRecord(record, traceId, tagId);
      if (traceSet.contains(traceId) == false)
        continue;
      if (!checkTagIdIsNumber(tagId))
      {
        context.getCounter("Error", "tag_id not a number").increment(1);
        continue;
      }
      Vector<String> ret = traceListMap.get(tagId);
      if (ret == null) {
        ret = new Vector<String>();
      }
      ret.add(traceId);
      traceListMap.put(tagId, ret);
    }    
  }

我好像得到了一个新的重复......在那种情况下我不知道如何消除重复,有人可以给我一些建议吗?

更新 2015-5-13 21:15:12:

有些人给出了一个 boolean 参数来消除重复,但我知道 Robert C. Martin 的 Clean Code Tip #12:消除 boolean 参数。(您可以通过 google 获取更多详细信息)。

您能对此发表一些评论吗?

最佳答案

更改的部分需要 String tagIdString traceId 的值,因此我们将从提取一个采用这些参数的接口(interface)开始:

public static class PerformingInterface {
     void accept(String tagId, String traceId);
}

然后将公共(public)部分提取到这个方法中:

  private static void doSomething(Context context, PerformingInterface perform) throws IOException
  {
    String traceId = null, tagId = null;
    for (Record record : context.getContext().readCacheTable("subscribe")) {
      getTraceIdAndTagIdFromRecord(record, traceId, tagId);
      if (traceSet.contains(traceId) == false)
        continue;
      if (!checkTagIdIsNumber(tagId))
      {
        context.getCounter("Error", "tag_id not a number").increment(1);
        continue;
      }
      perform.accept(tagId, traceId);
    }    
  }

然后以两种不同的方式调用这个方法:

private static void getRequiredTag(Context context) throws IOException {
    doSomething(context, new PerformingInterface() {
         @Override public void accept(String tagId, String traceId) {
              tagSet.add(tagId);
         }
    });
}

private static void addTagToTraceId(Context context) throws IOException {
    doSomething(context, new PerformingInterface() {
         @Override public void accept(String tagId, String traceId) {
             Vector<String> ret = traceListMap.get(tagId);
             if (ret == null) {
                 ret = new Vector<String>();
             }
             ret.add(traceId);
             traceListMap.put(tagId, ret);
         }
    });
}

注意,我这里使用的是lambdas,这是Java 8的一个特性(BiConsumer也是Java 8中定义的一个函数式接口(interface)),但是完全可以在Java 7中完成同样的事情而且更少,它只需要一些更冗长的代码。

您的代码的一些其他问题:

  • 太多的东西是静态的
  • Vector类较旧,更推荐使用ArrayList(如果需要同步,将其包裹在Collections.synchronizedList中)
  • 始终使用牙套,即使是单线牙套也是如此

关于java - 如何消除for循环中的重复代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30215281/

相关文章:

java - 用java计算月份和时差?

Java内存泄漏与字符串?为什么这会消耗和崩溃

ios - 我怎样才能在一个额外的功能中外包这种重复的代码味道? iOS Swift 函数

ruby-on-rails - 如何使用元编程进行 DRY?

java - 如何在 Spring Boot 应用程序中将数据库架构更改从源数据库同步到目标数据库

java堆内存问题

javascript - 最佳实践 - DRY 违规 Rails <-> JavaScript

go - 如何组合两个仅参数类型不同的函数

java - 如何使用java在文本文件中的特定列/索引上写入数据

html - 在 XSLT 中有条件地嵌套元素