帮助重构这个混乱的嵌套 if 方法

发布于 2024-07-11 17:10:51 字数 1452 浏览 7 评论 0原文

好吧,我想要一些意见,如何解决这个混乱的方法!

它有很多嵌套的“if”语句。

但意识到我必须确切地知道该方法在哪里失败,目前在每个相应的“else”子句中我正在记录错误(失败的“if”条件”)。

注意:忽略事物背后的任何逻辑,请关注样式和结构,因为我已经编写了所有函数名称等。

这是骨架结构:

   public void MyMethod()
{

   try
   {
    bool tryAgain = false;

    string filename = DownloadFile();

    if( IsFileFormatOk(filename) )
    {

        blah = GetBlah(filename);

        if(blah.ID > 0)
        {

            if(ImportFile(filename)
            {

                string username = GetUserFromFile(filename);

                if(isValidUser(username))
                {

                    // few more levels to go
                    //
                    //
                    //

                }
                else
                {
                    LogError(filename, ...); // specific to this if statement
                    tryAgain = true;
                }


            }
            else
            {

                LogError(filename, ...); // specific to this if statement
                tryAgain = true;
            }

        }
        else
        {
            LogError(filename, ...); // specific to this if statement
            tryAgain = true;
        }

    }
    else
    {
        LogError(filename, ...); // specific to this if statement
        tryAgain = true;
    }

   }
   catch
   {
   }
   finally
   {
    if(tryAgain)
    {
        // blah
    }
   }


}

Ok I want some opinions how I can fix this mess of a method!

It has WAY to many nested 'if' statements.

But realize I have to know exactly where the method fails, currently in each of the respective 'else' clause I am logging the error (the failed 'if' condition').

Note: ignore any logic behind the things, please focus on the style and structure as I have made all the function names up etc.

Here is the skeleton structure:

   public void MyMethod()
{

   try
   {
    bool tryAgain = false;

    string filename = DownloadFile();

    if( IsFileFormatOk(filename) )
    {

        blah = GetBlah(filename);

        if(blah.ID > 0)
        {

            if(ImportFile(filename)
            {

                string username = GetUserFromFile(filename);

                if(isValidUser(username))
                {

                    // few more levels to go
                    //
                    //
                    //

                }
                else
                {
                    LogError(filename, ...); // specific to this if statement
                    tryAgain = true;
                }


            }
            else
            {

                LogError(filename, ...); // specific to this if statement
                tryAgain = true;
            }

        }
        else
        {
            LogError(filename, ...); // specific to this if statement
            tryAgain = true;
        }

    }
    else
    {
        LogError(filename, ...); // specific to this if statement
        tryAgain = true;
    }

   }
   catch
   {
   }
   finally
   {
    if(tryAgain)
    {
        // blah
    }
   }


}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

凉墨 2024-07-18 17:10:51

我将努力更改您的逻辑,以便您可以尽快从该方法返回,而不是嵌套更多逻辑。 例如:

//  GOOD
if (!file.exists())
    return;
// Rest of the code

// BAD
if (file.exists()){
    // Code goes here
}
return;

这可能有助于删除一些嵌套并使事情变得不那么复杂。

I would work on changing your logic so you can return from the method as soon as possible instead of nesting more logic. Fore example:

//  GOOD
if (!file.exists())
    return;
// Rest of the code

// BAD
if (file.exists()){
    // Code goes here
}
return;

This may help remove some nesting and make things less complicated.

国产ˉ祖宗 2024-07-18 17:10:51

我猜想有相当多的逻辑等待在其他地方提取,但无论如何,这里有另一种扁平化嵌套的方法:

try
{
  if( !IsFileFormatOk(filename) )
    throw new MySpecificException(...); // pass specific log params

  blah = GetBlah(filename);

  if(blah.ID <= 0)
    throw new MySpecificException(...); // pass specific log params

  if(!ImportFile(filename)
    throw new MySpecificException(...); // pass specific log params

  string username = GetUserFromFile(filename);

  // ...
}
catch (MySecificException e)
{
  LogError(filename, e.LogParams)
  // blah
}

I would guess there's quite a bit of logic that's waiting to be extracted elsewhere, but in any case here's another way to flatten the nesting:

try
{
  if( !IsFileFormatOk(filename) )
    throw new MySpecificException(...); // pass specific log params

  blah = GetBlah(filename);

  if(blah.ID <= 0)
    throw new MySpecificException(...); // pass specific log params

  if(!ImportFile(filename)
    throw new MySpecificException(...); // pass specific log params

  string username = GetUserFromFile(filename);

  // ...
}
catch (MySecificException e)
{
  LogError(filename, e.LogParams)
  // blah
}
一曲爱恨情仇 2024-07-18 17:10:51

您可以首先将顶级 if (true 分支) 放入单独的方法中。 并继续直到满意为止。

因此,通常您将: 更改

if (condition) {
  // Block1
} else {
  // Block2
}

if (condition) {
  Block(...);
} else {
  Block2(...);
}

请注意需要传递给新方法的局部变量。

You can start by putting the toplevel if (true branch) in a separate method. And continue until satisfied.

So generally you change:

if (condition) {
  // Block1
} else {
  // Block2
}

Into

if (condition) {
  Block(...);
} else {
  Block2(...);
}

Please beware of the local variables that need to be passed tot the new method.

童话里做英雄 2024-07-18 17:10:51

您应该尝试让您调用的所有方法在发生错误时抛出异常。 抛出的异常应该包含您希望记录的任何错误消息。 创建一个 LogError() 方法,该方法接受任何异常并记录嵌入的消息。 像这样(伪代码):

MyMethod()
{
  try
  {
    string filename = DownloadFile()
    blah = GetBlah(filename)
    ImportFile(filename)
    ...
  }
  catch DownloadFileException, GetBlahException, ImportFileException e
  {
    LogError(e)
  }
}

当然,您必须创建所有这些异常,但这非常简单。 在大多数语言中,您只需对顶级 Exception 对象进行子类化即可。

You should try having all of the methods that you are calling throw an exception in case of an error. The exceptions thrown should contain whatever error message you wish to log. Create a LogError() method which takes any exception and logs the embedded message. Like this (pseudo-code):

MyMethod()
{
  try
  {
    string filename = DownloadFile()
    blah = GetBlah(filename)
    ImportFile(filename)
    ...
  }
  catch DownloadFileException, GetBlahException, ImportFileException e
  {
    LogError(e)
  }
}

Of course, you will have to create all of those Exceptions, but that is pretty trivial. In most languages you just subclass whatever the top level Exception object is.

温柔少女心 2024-07-18 17:10:51

编辑:既然我知道有这么多级别,我们需要采取另一种方法。 我不知道“重试”位中有什么,但您需要更改逻辑,以便它测试失败案例,而不是成功案例。 如果失败,记录并返回(或以某种方式执行重试所需的任何操作)。 否则,你可以继续跳出“如果”。

if(EndOfWorld)
{
    WriteLastLogEntryEver();
    return; //run away
}

//we're safe (for now)
ChargeOnAhead();

在我知道嵌套 if 的级别之前,我提出了以下建议。

public void MyMethod()
{

   try
   {
    bool tryAgain = false;

    string filename = DownloadFile();

    if( IsFileFormatOk(filename) )
    {

        tryAgain = DoBlah(filename, ...);
    }
    else
    {
        LogError(filename, ...); // specific to this if statement
        tryAgain = true;
    }

   }
   catch
   {
   }
   finally
   {
    if(tryAgain)
    {
        // blah
    }
   }


}

private bool DoImport(string filename, blah)
{

    if(ImportFile(filename))
    {

            // and so forth!
            return false;
    }

    LogError(filename, ...); // specific to this if statement
    return true;
}

private bool DoBlah(string filename)
{
        blah = GetBlah(filename);

        if(blah.ID > 0)
        {

            return DoImport(filename, ...);

        }

        LogError(filename, ...); // specific to this if statement
        return true;

}

我确信您可以对此进行更多重构,并将 // 等 拉入新方法中。 这取决于您需要来回传递多少东西。 如果您传递的参数太多,请考虑作为参数或类字段是否更有意义。


Edit: Now that I know there are so many levels, we need to take another approach. I don't know what's in the "try again" bit, but you need to change around the logic so it tests for a failure case, not a success case. If it fails, log and return (or somehow do whatever try again entails). Otherwise, you can keep going outside the if.

if(EndOfWorld)
{
    WriteLastLogEntryEver();
    return; //run away
}

//we're safe (for now)
ChargeOnAhead();

Before I knew there were many more levels of nested if, I suggested the following.

public void MyMethod()
{

   try
   {
    bool tryAgain = false;

    string filename = DownloadFile();

    if( IsFileFormatOk(filename) )
    {

        tryAgain = DoBlah(filename, ...);
    }
    else
    {
        LogError(filename, ...); // specific to this if statement
        tryAgain = true;
    }

   }
   catch
   {
   }
   finally
   {
    if(tryAgain)
    {
        // blah
    }
   }


}

private bool DoImport(string filename, blah)
{

    if(ImportFile(filename))
    {

            // and so forth!
            return false;
    }

    LogError(filename, ...); // specific to this if statement
    return true;
}

private bool DoBlah(string filename)
{
        blah = GetBlah(filename);

        if(blah.ID > 0)
        {

            return DoImport(filename, ...);

        }

        LogError(filename, ...); // specific to this if statement
        return true;

}

I'm sure you could refactor this a bit more and pull the // and so forth into a new method as well. It depends on how much stuff you're going to have to pass back and forth. And if you're passing too much, consider if it makes more sense to be a parameter or a class field.


舞袖。长 2024-07-18 17:10:51

这是 jjnguy 的建议,已实施:

public void MyMethod() {
    try
    {
        bool tryAgain = false;
        string filename = DownloadFile();

        if( !IsFileFormatOk(filename) )
        {
            LogError(filename, ...); // specific to this if statement
            tryAgain = true;
            return;
        }

        blah = GetBlah(filename);
        if(blah.ID <= 0)
        {
            LogError(filename, ...); // specific to this if statement
            tryAgain = true;
            return;
        }

        if(!ImportFile(filename))
        {
            LogError(filename, ...); // specific to this if statement
            tryAgain = true;
            return;
        }

        string username = GetUserFromFile(filename);

        if(!isValidUser(username))
        {
            LogError(filename, ...); // specific to this if statement
            tryAgain = true;
            return
        }

        // few more levels to go
        //

    finally
    {
        if(tryAgain)
        {
            // blah
        }
   }
}

Here's jjnguy's suggestion, implemented:

public void MyMethod() {
    try
    {
        bool tryAgain = false;
        string filename = DownloadFile();

        if( !IsFileFormatOk(filename) )
        {
            LogError(filename, ...); // specific to this if statement
            tryAgain = true;
            return;
        }

        blah = GetBlah(filename);
        if(blah.ID <= 0)
        {
            LogError(filename, ...); // specific to this if statement
            tryAgain = true;
            return;
        }

        if(!ImportFile(filename))
        {
            LogError(filename, ...); // specific to this if statement
            tryAgain = true;
            return;
        }

        string username = GetUserFromFile(filename);

        if(!isValidUser(username))
        {
            LogError(filename, ...); // specific to this if statement
            tryAgain = true;
            return
        }

        // few more levels to go
        //

    finally
    {
        if(tryAgain)
        {
            // blah
        }
   }
}
ぺ禁宫浮华殁 2024-07-18 17:10:51

对于这类问题,http://refactormycode.com/ 非常有用。

尽管 SO 人员也确实致力于重构一些代码。 ;)

For these kind of questions, http://refactormycode.com/ is very useful.

Although the SO people are really committed to refactoring some code, too. ;)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文