首页 > 代码库 > 怎样避免“if”嵌套

怎样避免“if”嵌套

前几日在浏览stackoverflow网站时,偶然看到别人提的“How to avoid ‘if’ chains” 的问题,觉得这是一个编程人员在编程时很容易就碰到的问题,而且我自己在看一些源码时也遇到过这种编程方式,因此,对这个问题进行一点总结。

if嵌套的情况很多,下面列出一些情况,并给出了相对来说比较简洁的书写方式以供参考:

1、使用一个guard来使用代码变得平坦

a、代码如下:

if (ok)
{
    DoSomething();
}
else
{
    _log.Error("oops");
    return;
}

可以替换成:

if (!ok)
{
    _log.Error("oops");
    return;
} 
DoSomething(); //notice how this is already farther to the left than the example above

b、代码如下:

ok = DoSomething1();
if (ok)
{
    ok = DoSomething2();
    if (ok)
    {
        ok = DoSomething3();
        if (!ok)
        {
            _log.Error("oops");  //Tip of the Arrow
            return;
        }
    }
    else
    {
       _log.Error("oops");
       return;
    }
}
else
{
    _log.Error("oops");
    return;
}

可以改写成:

ok = DoSomething1();
if (!ok)
{
    _log.Error("oops");
    return;
} 
ok = DoSomething2();
if (!ok)
{
    _log.Error("oops");
    return;
} 
ok = DoSomething3();
if (!ok)
{
    _log.Error("oops");
    return;
} 
ok = DoSomething4();
if (!ok)
{
    _log.Error("oops");
    return;
}

2、最后有非条件执行代码的情况,伪代码如下:

bool conditionA = executeStepA();
if (conditionA){
    bool conditionB = executeStepB();
    if (conditionB){
        bool conditionC = executeStepC();
        if (conditionC){
            ...
        }
    }
}
executeThisFunctionInAnyCase();

函数executeStepX当且仅当前面的条件成立时才执行,而函数executeThisFunctionInAnyCase则在最后必需执行,而不管其它条件是否成立。

a、使用条件与(&&),利用条件短路的特性

if (executeStepA() && executeStepB() && executeStepC()){
    ...
}
executeThisFunctionInAnyCase();

b、使用finally

try
{
bool conditionA = executeStepA();
if (!conditionA) return;

bool conditionB = executeStepB();
if (!conditionB) return;

bool conditionC = executeStepC();
if (!conditionC) return;
}
finally
{
    executeThisFunctionInAnyCase();
}

c、将条件执行用一个函数包起来

void foo()
{
  bool conditionA = executeStepA();
  if (!conditionA) return;

  bool conditionB = executeStepB();
  if (!conditionB) return;

  bool conditionC = executeStepC();
  if (!conditionC) return;
}

void bar()
{
  foo();
  executeThisFunctionInAnyCase();
}

d、使用goto语句

int foo() {
    int result = /*some error code*/;
    if(!executeStepA()) goto cleanup;
    if(!executeStepB()) goto cleanup;
    if(!executeStepC()) goto cleanup;

    result = 0;
cleanup:
    executeThisFunctionInAnyCase();
    return result;
}

e、利用条件的传递

bool condition = true; // using only one boolean variable
if (condition) condition = executeStepA();
if (condition) condition = executeStepB();
if (condition) condition = executeStepC();
...
executeThisFunctionInAnyCase();

f、使用异常

try {
    executeStepA();
    executeStepB();
    executeStepC();
}
catch (...) {
executeThisFunctionInAnyCase();
}

g、使用假循环

while(true)
{
    bool conditionA = executeStepA();
if (!conditionA) break;
bool conditionB = executeStepB();
if (!conditionB) break;
bool conditionC = executeStepC();
if (!conditionC) break;
    break;  //important
}
executeThisFunctionInAnyCase();

h、利用对象的生命周期

class MyContext
{
   ~MyContext()
   {
        executeThisFunctionInAnyCase();
   }
}

void MainMethod()
{
    MyContext myContext = new MyContext();
    
bool conditionA = executeStepA();
	if (!conditionA) return;

	bool conditionB = executeStepB();
	if (!conditionB) return;

	bool conditionC = executeStepC();
	if (!conditionC) return;

    //DoSomethingNoMatterWhat will be called when myContext goes out of scope
}

其中,最简单的是利用条件短路,而最复杂的是利用对象的生命周期。总结了这此情况和方法供大家参考,当然,可能还有很多其它的情况和处理方法,希望读者踊跃留言。