5

我有一个逻辑情况,最好将其描述为两个“团队”试图赢得一项任务。此任务的结果可能是一个获胜者、平局(平局)或没有获胜者(僵局)。

目前,我正在使用这样的嵌套 if/else 语句:

// using PHP, but the concept seems language agnostic.
if ($team_a->win()) {
    if ($team_b->win()) {
        //  this is a draw
    } else {
        //  team_a is the winner
    }
} else {
    if ($team_b->win()) { 
        //  team_b is the winner
    } else {
        //  This is a stalemate, no winner.
    }
}

这似乎有点像意大利面条和重复。我可以使用更合乎逻辑的 DRY 模式吗?

4

10 回答 10

6

另一种方法是 if win(a) && win(b) then Draw, else if win(a), else if win(b).

或者:

if win(a) and win(b) then
   // Draw
else if win(a) then
   // a wins
else if win(b) then
   // b wins
else 
   // Stalemate
于 2010-12-23T23:45:02.013 回答
4

我不认为它可以做得比你目前正在做的更好。

一种替代方法是使用 switch 表达式:

switch (($team_a->win() << 1) + $team_b->win()) {
case 3:
    //  this is a draw
case 2:
    //  team_a is the winner
case 1:
    //  team_b is the winner
case 0:
    //  This is a stalemate, no winner.
}

然而,虽然它更干燥,但我认为这不会提高可读性。请注意,在某些语言中,$team_x->win()您需要编写($team_x->win() ? 1 : 0).

于 2010-12-23T23:44:26.297 回答
3
if($TeamA->win() && $TeamB->win()){
  // Tie
}else if($TeamA->win()){
  // Team A wins
}else if($TeamB->win()){
  // Team B wins
}else{
  // No winner
}

此外,根据您的 win() 方法的作用,在外部检查一次可能更有效,if...else因此它只运行一次检查:

$team_a = $TeamA->win();
$team_b = $TeamB->win();

if($team_a && $team_b){
  // Tie
}else if($team_a){
  // Team A wins
}else if($team_b){
  // Team B wins
}else{
  // No winner
}
于 2010-12-23T23:47:22.010 回答
2

为了简化您的嵌套语句:

if($team_a->win() and $team_b->win())
{
  // Draw
}
elseif($team_a->win())
}
  // Team A Won
}
elseif($team_b->win())
}
  // Team B Won
}
else
{
  // No Winner
}
于 2010-12-23T23:46:25.797 回答
1

这是@Mark Byers 版本的扩展版本,旨在使其背后的逻辑更加清晰。

$result_code = 0;
if ($team_a->win()) $result_code += 1;
if ($team_b->win()) $result_code += 2;
switch ($result_code) {
   case 0:
      //stalemate
   case 1:
      //a wins
   case 2:
      //b wins
   case 3:
      //draw
}

这是一个非常好的程序,这个数字在任何组合中都不会产生相同的结果,我认为您将来会有很多场合使用它。这与 *nix 权限中使用的逻辑相同,并且也可以使用 < 2 个操作数:如果它们是三个,则可以使用 4、2 和 1 等等。

在这种特殊情况下,它也加快了处理速度,因为您只调用了一次团队对象的方法。

于 2010-12-24T01:18:08.070 回答
1

当这种类型的逻辑被封装在一个方法中时,早期返回比 if {} else 块更具可读性:

function game_end($a,$b) {
    if ($team_a->win() && $team_b->win()) {
            //  this is a draw
            return;
    } 

    if ($team_a->win()) {
            //  team_a is the winner
            return ;
    }

    if ($team_b->win()) {
            //  team_b is the winner
            return ;
    }

    //  This is a stalemate, no winner.

}
于 2010-12-24T01:58:04.007 回答
0

你不能用更直接的说法吗...

就像是

IF(a AND b) THEN {a,b}
ELSE If (a AND NOT(b)) THEN {a}
ELSE If (not(a) AND NOT(b)) THEN { }
ELSE {b}

与其他一些帖子相比,这是非常易读的,但不是最简洁的。

于 2010-12-23T23:43:38.603 回答
0

如果您要分成两组,每组两人,请考虑:

if (win(a) != win(b)) {
    // common code when there's a winner, regardless of who
    if (win(a)) {
        // code specific to a winning
    } else {
        // code specific to b winning
    }
} else {
    // common code for a non-result
    if (win(a)) {
        // code specific to a draw
    } else {
        // code specific to a stalemate
    }
}

如果您处于两个位置之一有一些通用代码的最佳位置,这可能会很有用,但是不值得或不可能抽象成一个函数并从 and 的四个块中的两个块中if/else if调用switch/case它.

于 2010-12-24T02:47:01.743 回答
0

就像我在评论中所说的那样,我认为获胜条件及其确定位置是错误的。有什么问题(例如快速电子代码):

if ($team_a->score() > $team_b->score()) return 'Team A wins!';
else if ($team_a->score() < $team_b->score()) return 'Team B wins!';
else return 'It's a tie!';

(语法可能是错误的,但你明白了)

重构比尝试为自己创建的问题想出解决方案要好。

于 2010-12-28T15:51:24.707 回答
0

在这里寻找 DRY 模式的问题是错误的,因为问题既不够复杂,也不足以保证重构/简化,而且它的圈复杂度太低,无需担心意大利面条化。

这是一个算法问题,准确地说是一个布尔代数......而且是一个非常简单的引导问题。您必须至少进行 3 次比较和 4 次分支才能做出决定。

IF (A ^ B) -> draw
ELSE (!A ^ !B) -> no win
ELSE A -> a wins
ELSE -> b wins

用更少的东西来做逻辑是不可能的。这里唯一的冗余是重新计算$team_b->win()(只需计算两支球队的胜利并将它们放在 if 语句之前的本地变量中)。

于 2011-02-02T22:54:24.500 回答