重构复杂的if条件

时间:2010-05-05 10:21:44

标签: java refactoring conditional if-statement

任何人都可以提出最好的方法来避免大多数条件吗?我有下面的代码,我想避免大多数情况下如果条件,怎么办呢?任何解决方案都是很有帮助的;

if (adjustment.adjustmentAccount.isIncrease) {
    if (adjustment.increaseVATLine) {
        if (adjustment.vatItem.isSalesType) {
            entry2.setDebit(adjustment.total);
            entry2.setCredit(0d);
        } else {
            entry2.setCredit(adjustment.total);
            entry2.setDebit(0d);
        }
    } else {
        if (adjustment.vatItem.isSalesType) {
            entry2.setCredit(adjustment.total);
            entry2.setDebit(0d);
        } else {
            entry2.setDebit(adjustment.total);
            entry2.setCredit(0d);
        }
    }
} else {
    if (adjustment.increaseVATLine) {
        if (adjustment.vatItem.isSalesType) {
            entry2.setCredit(adjustment.total);
            entry2.setDebit(0d);
        } else {
            entry2.setDebit(adjustment.total);
            entry2.setCredit(0d);
        }
    } else {
        if (adjustment.vatItem.isSalesType) {
            entry2.setDebit(adjustment.total);
            entry2.setCredit(0d);
        } else {
            entry2.setCredit(adjustment.total);
            entry2.setDebit(0d);
        }
    }
}

10 个答案:

答案 0 :(得分:18)

如何解决这个问题......让我们提取几种方法,以便我们更好地了解逻辑。

private void a() {
    entry2.setDebit(adjustment.total);
    entry2.setCredit(0d);
}
private void b() {
    entry2.setCredit(adjustment.total);
    entry2.setDebit(0d);
}

if (adjustment.adjustmentAccount.isIncrease) {
    if (adjustment.increaseVATLine) {
        if (adjustment.vatItem.isSalesType) {
            a();
        } else {
            b();
        }
    } else {
        if (adjustment.vatItem.isSalesType) {
            b();
        } else {
            a();
        }
    }
} else {
    if (adjustment.increaseVATLine) {
        if (adjustment.vatItem.isSalesType) {
            b();
        } else {
            a();
    }
} else {
    if (adjustment.vatItem.isSalesType) {
        a();
    } else {
        b();
    }
}

现在,看看它,第一个阻止

if (adjustment.increaseVATLine) {
    if (adjustment.vatItem.isSalesType) {
        a();
    } else {
        b();
    }
} else {
    if (adjustment.vatItem.isSalesType) {
        b();
    } else {
        a();
    }
}
如果a()adjustment.increaseVATLine具有相同的值,则{p>仅等于执行adjustment.vatItem.isSalesType,否则为b()。所以我们可以减少它:

if (adjustment.adjustmentAccount.isIncrease) {
    if (adjustment.increaseVATLine == adjustment.vatItem.isSalesType) {
        a();
    } else {
        b();
    }
} else {
    if (adjustment.increaseVATLine) {
        if (adjustment.vatItem.isSalesType) {
            b();
        } else {
            a();
        }
    } else {
        if (adjustment.vatItem.isSalesType) {
            a();
        } else {
            b();
        }
    }
}

剩下的区块是相同的,只是反转a()b()

if (adjustment.adjustmentAccount.isIncrease) {
    if (adjustment.increaseVATLine == adjustment.vatItem.isSalesType) {
        a();
    } else {
        b();
    }
} else {
    if (adjustment.increaseVATLine == adjustment.vatItem.isSalesType) {
        b();
    } else {
        a();
    }
}

所以我们开始看到逻辑。如果它是一个增加,并且increaseVATLine匹配isSalesType,那么我们借记,否则信用,但如果它是减少,那么我们只有在它们不匹配时才会记入。表达这个的好方法是什么?那么,对于一个人来说,将a()和b()命名为更聪明 - 现在我们可以看到他们正在做什么

if (adjustment.adjustmentAccount.isIncrease) {
    if (adjustment.increaseVATLine == adjustment.vatItem.isSalesType) {
        debitEntry();
    } else {
        creditEntry();
    }
} else {
    if (adjustment.increaseVATLine == adjustment.vatItem.isSalesType) {
        creditEntry();
    } else {
        debitEntry();
    }
}

现在它仍然有点清晰。当帐户是增加帐户和增加的增值税行,销售类型,或者减少时,借记帐户,或者减少增值税行或者是销售类型,但不是两者。这个真相表有帮助吗?第一列是adjustmentAmount.isIncrease;第二个是adjustment.increaseVATLine;第三是adjustment.vatItem.isSalesType。第四栏是D代表借方,C代表贷方;在括号中是标志中的TRUE值的数量。

TTT -> D (3) 
TFF -> D (1) 
TTF -> C (2)
TFT -> C (2) 
FTT -> C (2) 
FFF -> C (0)
FTF -> D (1) 
FFT -> D (1)

现在您可以看到为什么@Xavier Ho的解决方案有效;奇数总数都是借方,偶数都是贷方。

这只是一条探索之路;我希望它有用。

答案 1 :(得分:8)

我还没有彻底验证逻辑,但这是基本的想法:

amt = adjustment.total
if (adjustment.adjustmentAccount.isIncrease
    ^ adjustment.increaseVATLine
    ^ adjustment.vatItem.isSalesType)
{
    amt = -amt;
}

entry2.setCredit(amt > 0 ? amt : 0);
entry2.setDebit(amt < 0 ? -amt : 0);

我应该注意到这个逻辑略有不同,因为它正确地处理了adjustment.total的负值,而原始似乎假设(可能是正确的)该值总是非负的。

答案 2 :(得分:6)

你可以使用这样的真值表:

debit = ((isIncrease && increaseVATLine && !isSalesType) ||
         (isIncrease && !increaseVATLine && isSalesType) ||
         (!isIncrease && increaseVATLine && isSalesType) ||
         (!isIncrease && !increaseVATLine && !isSalesType)) ? 0 : adjustment.total;
entry2.setCredit(debit);

没有任何ifs,你可以很容易地看到借记卡是0.同样的信用额度。

答案 3 :(得分:6)

我认为这很有效。我基本上概括了你的布尔逻辑。下次,尝试绘制一些图表以帮助您清除思路。

编辑:我想从本文的评论中指出,Marcelo和BlueRaja提供的XOR解决方案功能相同。

/* This is to avoid a crazy 3-way switch. Generalised.
 * Instead of using a complicated if-else branch, we can use the number of true
 * and false to entail the intended action. */
/* This is the same as a ^ b ^ c (chained XOR), 
 * which is used to count the parity of truth values. */
int a = adjustment.adjustmentAccount.isIncrease ? 1 : 0;
int b = adjustment.increaseVATLine ? 1 : 0;
int c = adjustment.vatItem.isSalesType ? 1 : 0;

if ((a + b + c) % 2 == 1)
{
    entry2.setDebit(adjustment.total);          // Odd number of trues
    entry2.setCredit(0d);
}
else
{
    entry2.setCredit(adjustment.total);         // Even number of trues
    entry2.setDebit(0d);
}

答案 4 :(得分:5)

马丁史密斯评论我将补充:

请记住,Karnaugh可以帮助您简化条件。

答案 5 :(得分:4)

问题已得到解答,但我会在这里发布那些关心更清洁解决方案的人:

//Set debit if exactly one or all three are true, else set credit
if(adjustment.adjustmentAccount.isIncrease ^ adjustment.increaseVATLine ^
   adjustment.vatItem.isSalesType)
{
    entry2.setDebit(adjustment.total);
    entry2.setCredit(0d);
}
else
{
    entry2.setCredit(adjustment.total);
    entry2.setDebit(0d);
}

答案 6 :(得分:3)

看起来你只有2个案例,所以你可以将它们与OR等结合起来。

        if (<case1expression>) {
            entry2.setCredit(adjustment.total);
            entry2.setDebit(0d);
        } else {
            entry2.setDebit(adjustment.total);
            entry2.setCredit(0d);
        }

答案 7 :(得分:1)

如果你有条件逻辑(例如,如果满足条件就做某事),你为什么要试着避免它们呢?

答案 8 :(得分:1)

在一定程度上通常可以采取的措施是继承。

例如,如果您有两个类IncreaseNonIncrease,它们是同一个超类的子类,那么您可以使用方法doSomething来做 - 根据您目前的任何类别有。然后你不必检查“如果对象是做X”,而只是调用.doSomething()并且它会做它想做的任何事情。

然后你可以更进一步,拥有越来越多的子类来进一步“细化”和“避免更多的ifs”。

可能还有其他可能性(主要取决于您的环境/要求),如函数指针,委托,strategy pattern (GoF)或此类构造。

答案 9 :(得分:1)

最佳解决方案是遵循设计模式。 基于状态的设计模式为每个州定义一个类。

然后状态类封装了该特定状态的操作过程。 这不仅可以防止大量的if -else语句网格。