是否有任何技术用标志参数拆分方法?

问题描述:

我有一个标志参数的方法。我认为将布尔值传递给方法是一种不好的做法(使签名复杂化,违反了“每种方法做一件事”的原则)。我认为将该方法分解为两种不同的方法会更好。但如果我这样做,这两种方法会非常相似(代码重复)。是否有任何技术用标志参数拆分方法?

我想知道是否有一些通用的技术用于将标志参数拆分为两个独立的方法。

这里是我的方法(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; 
} 

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

在这个例子中,你有两种选择,在我看来。

说你希望将电话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(),正如许多人已经提出的那样。

+0

好主意,但使用静态内部类来实现过滤器。 – Ralph 2010-11-24 12:09:06

  • 你可以尝试在一个单一的方法来提取通用的功能只有使用特定功能
  • 你可以创建一个私有方法与该国旗,并从两种公共方法调用它。因此,你的公共API不会有'复杂'的方法签名,你不会有重复的代码
  • 做一个方法返回两个值,并在每个调用方(公共方法)中选择一个。

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

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

+0

+1优化。否则,该方法应该被调用两次以获得死亡和活着的邻居。 – khachik 2010-11-24 11:51:36

如果你不喜欢你的签名布尔,你可以添加两种不同的方法,没有它,重构来private主要的一个:

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

OR

你可以编写一个结果类别int数组作为用于存储两个结果的输出参数;这会让你摆脱恼人的布尔参数。

+1

我宁愿使用公有委托方法的私有方法而不是其他建议。 – heikkim 2010-11-24 12:13:51

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; 
} 

像Bozho说:但是,但是在角落找寻其他方式结合点2和3:

创建一个(可能的私有方法)返回两者(活的和死)和(仅当您需要在大多数情况下,生死未卜独立),然后添加了两个方法,挑死或既出结果:

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

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

  • 复制方法并创建两个版本,一个是真硬编码,另一个是真硬编码。您的重构工具应该帮助您内联这个常量并根据需要删除代码。
  • 为了向后兼容,重新创建调用如上所述的正确/错误方法的方法。然后你可以内联这种方法。

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

我会倾向于保留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); 
}