如何避免多个嵌套的IF

时间:2010-09-08 08:49:49

标签: c# design-patterns exception if-statement

我目前正在尝试将我的程序重组为更多OO并更好地实现已知模式等。

我有很多嵌套的IF语句,想要摆脱它们。我怎么能这样做?我的第一种方法是用例外来完成它,例如。

public static Boolean MyMethod(String param) {
 if (param == null)
  throw new NullReferenceException("param may not be null");

 if (param.Equals("none") || param.Equals("0") || param.Equals("zero"))
  throw new ArgumentNullException("param may not be zero");

 // Do some stuff with param
 // This is not executed if param is null, as the program stops a soon
 // as one of the above exceptions is thrown
}

该方法用于应用程序的主类,例如

static void Main() {
 try {
  Boolean test = MyClass.MyMethod(null); // Will throw an exception
 } catch (Exception ex) {
  MessageBox.Show(ex.Message, "Error");
 }

我认为这非常好,因为它可以防止嵌套语句和几乎所有方法操作在一个层次上很好地排列。

与IF语句一样,该方法看起来像这样

public Boolean MyMethod(String param) {
 if (param != null) {
  if (!param.Equals("none") && !param.Equals("0") && !param.Equals("zero")) {
   // Do some stuff with param
  } else {
   MessageBox.Show("param may not be zero", "Error");
 } else {
  MessageBox.Show("param may not be null", "Error");
 }
}

我觉得非常非常难看并且难以维护。

现在,问题是;这种方法?我知道,这可能是主观的,但是你如何克服嵌套的IF(1或2级并不是那么糟糕,但之后会变得更糟......)

6 个答案:

答案 0 :(得分:18)

您的问题被称为箭头反模式。

有一些务实的方法,例如你在样本中展示的Guard语句,对整个设计模式,避免if(和其他)一起......

关于如何解决这些问题的大量资源:

http://www.codinghorror.com/blog/2006/01/flattening-arrow-code.html

http://www.lostechies.com/blogs/chrismissal/archive/2009/05/27/anti-patterns-and-worst-practices-the-arrowhead-anti-pattern.aspx

http://elegantcode.com/2009/08/14/observations-on-the-if-statement/

答案 1 :(得分:16)

这实际上取决于他们的目的。在第一个示例中,if语句用于执行合同,确保方法的输入满足特定要求。在这些情况下,我自己的代码往往看起来很像你的代码。

在使用if块来控制方法的流程(而不是强制执行合同)的情况下,有时可能会有点困难。有时我会遇到类似以下(非常简化)示例的代码:

private void SomeMethod()
{
    if (someCondition == true)
    {
        DoSomething();
        if (somethingElse == true)
        {
           DoSomethingMore();
        }
    }
    else
    {
        DoSomethingElse();
    }
}

在这种情况下,似乎该方法有几个职责,所以在这种情况下我可能会选择将它分成几个方法:

private void SomeMethod()
{
    if (someCondition == true)
    {
        DoItThisWay();
    }
    else
    {
        DoSomethingElse();
    }
}

private void DoItThisWay()
{
    DoSomething();
    if (somethingElse == true)
    {
       DoSomethingMore();
    }
}

这使得每个方法都更简单,嵌套代码更少,并且如果给出了良好的名称,也可以提高可读性。

答案 2 :(得分:4)

您想要调查C#4 code contracts

经常使用的模式是DDD specification pattern来抽象if语句,尽管在你的情况下它可能不合适。

答案 3 :(得分:1)

答案 4 :(得分:1)

在这种情况下,也许AspectF可以帮到你:

public Boolean MyMethod(String param) {
 try {
  AspectF.Define
   .ErrorMsgIfNull(param, "must be not null")
   .ErrorMsgIfEquals(new string[] {"None", "Zero", "0"}, "may not be zero")
   //...
   // use your own "AspectFlets" you wrote
   //...
   .Do(() =>
    {
     // Do some stuff with param
     // This is not executed if param is null, as the program stops a soon
     // as one of the above exceptions is thrown
    });
}

如果你有几个条件要满足(或避免),这会产生一个丑陋的嵌套if,这种分解代码的方式可能会帮助你使事情更具描述性。

上面代码中的方法只是不存在的示例,但可以轻松实现。

答案 5 :(得分:0)

这是一个非常广泛的问题,因为它真的取决于if语句的功能。

当然,在可能的情况下,我尝试用交换机替换嵌套的if语句,但这并不总是可行。

检查参数有效性是一种很好的方法,但是看看它在代码中更高的位置,即具有throw语句,但不是抛出它的类中的catch。