假设我有这样的伪代码:

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

executeThisFunctionInAnyCase();

函数executeStepX当且仅当前一个成功时执行。 在任何情况下,executeThisFunctionInAnyCase函数都应该在最后被调用。 我在编程方面是一个新手,所以很抱歉提出一个非常基本的问题:有没有一种方法(例如在C/ c++中)以代码易读性为代价,避免长if链产生那种“金字塔式代码”?

我知道如果我们可以跳过executeThisFunctionInAnyCase函数调用,代码可以简化为:

bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;

但是约束是executeThisFunctionInAnyCase函数调用。 break语句可以以某种方式使用吗?


当前回答

为什么没有人给出最简单的解决方案?: D

如果你所有的函数都有相同的签名,那么你可以这样做(对于C语言):

bool (*step[])() = {
    &executeStepA,
    &executeStepB,
    &executeStepC,
    ... 
};

for (int i = 0; i < numberOfSteps; i++) {
    bool condition = step[i]();

    if (!condition) {
        break;
    }
}

executeThisFunctionInAnyCase();

对于简洁的c++解决方案,您应该创建一个接口类,其中包含一个执行方法,并将步骤包装在对象中。 然后,上面的解看起来像这样:

Step *steps[] = {
    stepA,
    stepB,
    stepC,
    ... 
};

for (int i = 0; i < numberOfSteps; i++) {
    Step *step = steps[i];

    if (!step->execute()) {
        break;
    }
}

executeThisFunctionInAnyCase();

其他回答

你可以使用switch语句

switch(x)
{
  case 1:
    //code fires if x == 1
    break;
  case 2:
    //code fires if x == 2
    break;

  ...

  default:
    //code fires if x does not match any case
}

等价于:

if (x==1)
{
  //code fires if x == 1
}
else if (x==2)
{
  //code fires if x == 2
}

...

else
{
  //code fires if x does not match any of the if's above
}

然而,我认为没有必要避免if-else-chains。switch语句的一个限制是它们只测试完全相等;也就是说,你不能测试“case x<3”——在c++中,它会抛出一个错误,在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();
}

使用深度嵌套的if(你的第一个变体)或者想要跳出“函数的一部分”通常意味着你确实需要一个额外的函数。

在阅读了所有的答案之后,我想提供一种新的方法,它在适当的情况下可能非常清晰易读:状态模式。

如果你将所有的方法(executeStepX)打包到一个对象类中,它可以有一个属性getState()

class ExecutionChain
{
    public:
        enum State
        {
          Start,
          Step1Done,
          Step2Done,
          Step3Done,
          Step4Done,
          FinalDone,
        };
        State getState() const;

        void executeStep1();
        void executeStep2();
        void executeStep3();
        void executeStep4();
        void executeFinalStep();
    private:
        State _state;
};

这将允许你将你的执行代码平铺成这样:

void execute
{
    ExecutionChain chain;

    chain.executeStep1();

    if ( chain.getState() == Step1Done )
    {
        chain.executeStep2();
    }

    if ( chain.getState() == Step2Done )
    {
        chain.executeStep3();
    }

    if ( chain.getState() == Step3Done )
    {
        chain.executeStep4();
    }

    chain.executeFinalStep();
}

通过这种方式,它易于阅读,易于调试,你有一个清晰的流控制,还可以插入新的更复杂的行为(例如,只有在至少执行Step2时才执行Special Step)……

我的问题与其他方法,如ok = execute();如果(execute()),则代码应该清晰易读,就像正在发生的事情的流程图一样。在流程图中有两个步骤:1。2执行。基于结果的决定

因此,您不应该将重要的重载方法隐藏在if语句或类似语句中,它们应该独立存在!

让执行函数在失败时抛出异常,而不是返回false。然后你的调用代码看起来像这样:

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

当然,我假设在您最初的示例中,执行步骤只会在步骤内发生错误的情况下返回false ?

已经有很多不错的答案了,但大多数答案似乎都牺牲了一些(诚然,很少)灵活性。一种不需要这种权衡的常见方法是添加状态/持续变量。当然,价格是需要跟踪的额外价值:

bool ok = true;
bool conditionA = executeStepA();
// ... possibly edit conditionA, or just ok &= executeStepA();
ok &= conditionA;

if (ok) {
    bool conditionB = executeStepB();
    // ... possibly do more stuff
    ok &= conditionB;
}
if (ok) {
    bool conditionC = executeStepC();
    ok &= conditionC;
}
if (ok && additionalCondition) {
    // ...
}

executeThisFunctionInAnyCase();
// can now also:
return ok;