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

发布于 2024-10-04 08:15:24 字数 906 浏览 8 评论 0原文

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

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

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

I have a method with a flag argument. I think that passing a boolean to a method is a bad practice (complicates the signature, violates the "each method does one thing" principle). I think splitting the method into two different methods is better. But if I do that, the two methods would be very similar (code duplication).

I wonder if there are some general techniques for splitting methods with a flag argument into two separate methods.

Here's the code of my method (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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

热情消退 2024-10-11 08:15:24

如果您不喜欢签名上的布尔值,您可以添加两种不带它的不同方法,将主要方法重构为 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数组作为输出参数,用于存储两个结果;这将使您摆脱烦人的布尔参数。

If you don't like the boolean on your signature, you could add two different methods without it, refactoring to private the main one:

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

OR

you could code a Result Class or int array as output parameter for storing both the results; this would let you get rid of the annoying boolean parameter.

任谁 2024-10-11 08:15:24

我想这取决于每个案例。

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

假设您想将调用 calculateNumOfLiveOrDeadNeighbors() 分成

两部分:

calculateNumOfLiveNeighbors() 

并且

calculateNumOfDeadNeighbors()

您可以使用 Template将循环移动到另一个方法的方法
您可以使用它在两种方法中对死/活细胞进行计数。

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() ,正如许多人已经建议的那样。

I guess it depends on every single case.

In this example you have two choices, in my opinion.

Say you want to split the call calculateNumOfLiveOrDeadNeighbors()

in two:

calculateNumOfLiveNeighbors() 

and

calculateNumOfDeadNeighbors()

You can use Template Method to move the loop to another method.
You can use it to count dead / alive cells in the two methods.

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

It's cumbersome, maybe not even worth the pain. You can, alternatively, use a monad to store the results of your statistics calculation and then use getDeadCounter() or getLiveCounter() on the monad, as many suggested already.

陌上青苔 2024-10-11 08:15:24
  • 您可以尝试在单个方法中提取通用功能,并且仅使用特定功能
  • 您可以使用该标志创建一个私有方法,并从两个公共方法中调用它。因此,您的公共 API 将不会具有“复杂”的方法签名,并且您不会有重复的代码
  • 来创建一个返回两个值的方法,并在每个调用者中选择一个(公共方法)。

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

  • you can try to extract the common functionality in a single method and only use the specific functionality
  • you can create a private method with that flag, and invoke it from the two public methods. Thus your public API will not have the 'complicated' method signature, and you won't have duplicated code
  • make a method that returns both values, and choose one in each caller (public method).

In the example above I think the 2nd and 3rd options are more applicable.

相守太难 2024-10-11 08:15:24

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

Seems like the most semantically clean approach would be to return a result object that contains both values, and let the calling code extract what it cares about from the result object.

空名 2024-10-11 08:15:24

就像Bozho所说:但是,但是以另一种方式结合第2点和第3点:

创建一个(可能的私有方法),它返回(活着和死了)并且(仅当您在大多数情况下需要分开死或活时)然后添加两个从结果中挑选出死亡或两者的方法:

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

Like Bozho said: But but combine point 2 and 3 in the other way arround:

Create a (possible private method) that returns both (living and dead) and (only if you need dead or alive seperate in the most cases) then add two methods that pick dead or both out of the result:

DeadLiveCounter calcLiveAndDead(..) {}
int calcLive(..) { return calcLiveAndDead(..).getLive; }
int calcDead(..) { return calcLiveAndDead(..).getDead; }
永不分离 2024-10-11 08:15:24

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

IMO, this so-called "each method does one thing" principle needs to be applied selectively. Your example is one where, it is probably better NOT to apply it. Rather, I'd just simplify the method implementation a bit:

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;
}
阳光的暖冬 2024-10-11 08:15:24

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

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

In terms of using refactoring, some things you can do are;

  • copy the method and create two version, one with true hard coded and the other false hard coded. Your refactoring tools should help you inline this constant and remove code as required.
  • recreate the method which calls the right true/false method as above for backward compatibility. You can then inline this method.
ˇ宁静的妩媚 2024-10-11 08:15:24

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

I would be inclined here to keep a map from the CellState enum to count, then add the LIVE and the SICK or the DEAD and the DEAD4GOOD as needed.

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);
}
迟月 2024-10-11 08:15:24

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

have a private method which is an exact copy and paste of what you currently have.
Then create two new methods, each with a more descriptive name that simply call your private method with appropriate boolean

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文