【问题标题】:How to avoid multiple nested IFs如何避免多个嵌套的 IF
【发布时间】:2010-09-08 08:49:48
【问题描述】:

我目前正在尝试重组我的程序,使其更加面向对象并更好地实现已知模式等。

我有很多嵌套的 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 级还不错,但之后会变得更糟......)

【问题讨论】:

  • 这可能只是示例代码,但您确实应该避免抛出异常。使用 ArgumentNullException 等。
  • 也许更重要的是你不应该抛出然后捕获这样的异常。
  • 这是示例代码,我总是尝试为案例抛出更好的命名异常。而且捕获当然不会以相同的方法发生,它是在应用程序的更高级别上完成的,或多或少是在它们冒泡给用户之前完成的。
  • 好吧,这更有意义。也许您可以更新问题以更清楚地反映这一点。
  • 除了例外,我认为这个问题非常好。这完全是为了阐明逻辑和可读性,这一章经常被跳过。

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


【解决方案1】:

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

有一些实用的方法,例如您在示例中显示的 Guard 语句,用于整个设计模式,避免将 if(和 else)放在一起......

关于如何解决它们的大量资源:

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/

【讨论】:

    【解决方案2】:

    这真的取决于他们的目的。在您的第一个示例中,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();
        }
    }
    

    这使得每个方法更简单,嵌套代码更少,如果方法名称好的话,还可以提高可读性。

    【讨论】:

    • 看我的评论 - 捕捉不是用同一种方法完成的,只是为了不用写几个方法;D
    【解决方案3】:

    你想调查C#4 code contracts

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

    【讨论】:

    • 这些合同是一件非常巧妙的事情。我会调查他们。
    • 规范模式:为什么不使用 Func 类型的参数?
    【解决方案4】:
    【解决方案5】:

    也许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 块,这种分解代码的方式可能会帮助您使事情更具描述性。

    以上代码中的方法只是示例,不存在,但很容易实现。

    【讨论】:

      【解决方案6】:

      这确实是一个相当广泛的问题,因为它实际上取决于 if 语句的功能。

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

      检查参数有效性是一个好方法,但要在代码中将其捕捉到更高的位置,即有 throw 语句,而不是在抛出它的类中的 catch。

      【讨论】:

      • 查看修改后的问题。这是懒惰,在实际代码中的处理方式不同。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多