我有一个带有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;
}
答案 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)
在上面的例子中,我认为第二和第三个选项更适用。
答案 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)
在使用重构方面,您可以做的一些事情是
答案 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)
有一个私有方法,它是您目前所拥有的精确复制和粘贴。 然后创建两个新方法,每个方法都有一个更具描述性的名称,只需使用适当的布尔值
调用私有方法