是否有任何技术可以使用flag参数拆分方法?

时间:2010-11-24 11:41:21

标签: java refactoring flags coding-style

我有一个带有flag参数的方法。我认为将布尔值传递给方法是一种不好的做法(使签名复杂化,违反了“每种方法做一件事”的原则)。我认为将方法分为两种不同的方法更好。但如果我这样做,这两种方法将非常相似(代码重复)。

我想知道是否有一些通用技术将带有flag参数的方法拆分为两个单独的方法。

这是我的方法代码(Java):

int calculateNumOfLiveOrDeadNeighbors(Cell c, int gen, boolean countLiveOnes) {
   int x = c.getX();
   int y = c.getY();
   CellState state;
   int aliveCounter = 0;
   int deadCounter = 0;
   for (int i = x - 1; i <= x + 1; i++) {
      for (int j = y - 1; j <= y + 1; j++) {
         if (i == x && j == y)
            continue;
         state = getCell(i, j).getCellState(gen);
         if (state == CellState.LIVE || state == CellState.SICK){
            aliveCounter++;
         }
         if(state == CellState.DEAD || state == CellState.DEAD4GOOD){
            deadCounter++;
         }
      }
   }
   if(countLiveOnes){
      return aliveCounter;
   }
   return deadCounter;
}

9 个答案:

答案 0 :(得分:5)

如果您不喜欢签名上的布尔值,可以在没有它的情况下添加两种不同的方法,重构为private主要方法:

int calculateNumOfLiveNeighbors(Cell c, int gen) {
  return calculateNumOfLiveOrDeadNeighbors(c, gen, true);
}
int calculateNumOfDeadNeighbors(Cell c, int gen) {
  return calculateNumOfLiveOrDeadNeighbors(c, gen, false);
}

您可以将结果类 int array 编码为输出参数,以存储结果;这会让你摆脱烦人的布尔参数。

答案 1 :(得分:4)

  • 您可以尝试在单个方法中提取常用功能,并仅使用特定功能
  • 您可以使用该标志创建一个私有方法,并从两个公共方法中调用它。因此,您的公共API将不具有“复杂”方法签名,并且您将没有重复代码
  • 创建一个返回两个值的方法,并在每个调用者中选择一个(公共方法)。

在上面的例子中,我认为第二和第三个选项更适用。

答案 2 :(得分:4)

我想这取决于每一个案例。

在这个例子中,我认为你有两个选择。

假设您要分割通话calculateNumOfLiveOrDeadNeighbors()

两个:

calculateNumOfLiveNeighbors() 

calculateNumOfDeadNeighbors()

您可以使用Template Method将循环移动到另一种方法。 您可以使用它来计算两种方法中的死/活细胞。

private int countCells(Cell c, int gen, Filter filter)
{
    int x = c.getX();
    int y = c.getY();
    CellState state;
    int counter = 0;
    for (int i = x - 1; i <= x + 1; i++) 
    {
        for (int j = y - 1; j <= y + 1; j++) 
        {
            if (i == x && j == y)
                continue;
            state = getCell(i, j).getCellState(gen);
            if (filter.countMeIn(state))
            {
                counter++;
            }
        }
    }
    return counter;
 }

 private interface Filter
 {
      boolean countMeIn(State state);
 }

 public int calculateNumOfDeadNeighbors(Cell c, int gen)
 {
     return countCells(c, gen, new Filter()
                       { 
                           public boolean countMeIn(CellState  state)
                           {
                              return (state == CellState.DEAD || state == CellState.DEAD4GOOD);
                           }
                        });
  }

 public int calculateNumOfLiveNeighbors(Cell c, int gen)
 {
     return countCells(c, gen, new Filter()
                       { 
                           public boolean countMeIn(CellState  state)
                           {
                              return (state == CellState.LIVE || state == CellState.SICK);
                           }
                        });
  }

这很麻烦,甚至可能不值得痛苦。或者,您可以使用monad存储统计信息计算的结果,然后在monad上使用getDeadCounter()getLiveCounter(),正如许多人所建议的那样。

答案 3 :(得分:1)

似乎最语义上最干净的方法是返回包含两个值的结果对象,并让调用代码从结果对象中提取它所关心的内容。

答案 4 :(得分:1)

IMO,这个所谓的“每个方法做一件事”原则需要有选择地应用。你的例子是一个,最好不要应用它。相反,我只是简化了方法实现:

int countNeighbors(Cell c, int gen, boolean countLive) {
   int x = c.getX();
   int y = c.getY();
   int counter = 0;
   for (int i = x - 1; i <= x + 1; i++) {
      for (int j = y - 1; j <= y + 1; j++) {
         if (i == x && j == y)
            continue;
         CellState s = getCell(i, j).getCellState(gen);
         if ((countLive && (s == CellState.LIVE || s == CellState.SICK)) ||
             (!countLive && (s == CellState.DEAD || s == CellState.DEAD4GOOD))) {
            counter++;
         }
      }
   }
   return counter;
}

答案 5 :(得分:1)

像Bozho所说的那样:但是在另一方面将第2点和第3点结合起来:

创建一个(可能的私有方法),返回(生和死)和(只有在大多数情况下你需要死或独立)然后添加两个方法,选择死或两个结果:

DeadLiveCounter calcLiveAndDead(..) {}
int calcLive(..) { return calcLiveAndDead(..).getLive; }
int calcDead(..) { return calcLiveAndDead(..).getDead; }

答案 6 :(得分:1)

在使用重构方面,您可以做的一些事情是

  • 复制方法并创建两个版本,一个使用真正的硬编码,另一个使用虚假硬编码。您的重构工具应该可以帮助您内联此常量并根据需要删除代码。
  • 重新创建调用上述正确的true / false方法的方法,以实现向后兼容性。然后,您可以内联此方法。

答案 7 :(得分:1)

我倾向于保持CellState枚举中的地图计数,然后根据需要添加LIVE和SICK或DEAD和DEAD4GOOD。

int calculateNumOfLiveOrDeadNeighbors(Cell c, int gen, boolean countLiveOnes) {
    final int x = c.getX();
    final int y = c.getY();
    final HashMap<CellState, Integer> counts = new HashMap<CellState, Integer>();
    for (CellState state : CellState.values())
        counts.put(state, 0);

    for (int i = x - 1; i < x + 2; i++) {
        for (int j = y - 1; j < y + 2; j++) {
            if (i == x && j == y)
                continue;
            CellState state = getCell(i, j).getCellState(gen);
            counts.put(state, counts.get(state) + 1);
        }
    }
    if (countLiveOnes)
        return counts.get(CellState.LIVE) + counts.get(CellState.SICK);
    else
        return counts.get(CellState.DEAD) + counts.get(CellState.DEAD4GOOD);
}

答案 8 :(得分:0)

有一个私有方法,它是您目前所拥有的精确复制和粘贴。 然后创建两个新方法,每个方法都有一个更具描述性的名称,只需使用适当的布尔值

调用私有方法