怎样避免“if”嵌套

来源:互联网 发布:linux命令复制覆盖 编辑:程序博客网 时间:2024/04/28 05:11

前几日在浏览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 variableif (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}

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

0 0