假设我有这样的伪代码:

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语句可以以某种方式使用吗?


当前回答

只做

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

就是这么简单。


由于三次编辑都从根本上改变了问题(如果算上版本1的修订,则是四次),我包括了我正在回答的代码示例:

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

executeThisFunctionInAnyCase();

其他回答

如果你的代码像你的例子一样简单,并且你的语言支持短路计算,你可以尝试这样做:

StepA() && StepB() && StepC() && StepD();
DoAlways();

如果您将参数传递给函数并返回其他结果,因此您的代码不能以以前的方式编写,那么许多其他答案将更适合解决这个问题。

这看起来像一个状态机,这很方便,因为您可以使用状态模式轻松实现它。

在Java中,它看起来像这样:

interface StepState{
public StepState performStep();
}

实现如下所示:

class StepA implements StepState{ 
    public StepState performStep()
     {
         performAction();
         if(condition) return new StepB()
         else return null;
     }
}

等等。然后你可以将大if条件替换为:

Step toDo = new StepA();
while(toDo != null)
      toDo = toDo.performStep();
executeThisFunctionInAnyCase();

只是一个边注;如果if作用域总是导致返回(或循环中断),则不要使用else语句。这可以节省大量的缩进。

如果条件被移动到单独的步骤下,条件可以被简化,这是一个c#伪代码,

其思想是使用编排而不是中央编排。

void Main()
{
    Request request = new Request();
    Response response = null;

    // enlist all the processors
    var processors = new List<IProcessor>() {new StepA() };

    var factory = new ProcessorFactory(processors);

    // execute as a choreography rather as a central orchestration.
    var processor = factory.Get(request, response);
    while (processor != null)
    {
        processor.Handle(request, out response);
        processor = factory.Get(request, response); 
    }

    // final result...
    //response
}

public class Request
{
}

public class Response
{
}

public interface IProcessor
{
    bool CanProcess(Request request, Response response);
    bool Handle(Request request, out Response response);
}

public interface IProcessorFactory
{
    IProcessor Get(Request request, Response response);
}   

public class ProcessorFactory : IProcessorFactory
{
    private readonly IEnumerable<IProcessor> processors;

    public ProcessorFactory(IEnumerable<IProcessor> processors)
    {
        this.processors = processors;
    }

    public IProcessor Get(Request request, Response response)
    {
        // this is an iterator
        var matchingProcessors = processors.Where(x => x.CanProcess(request, response)).ToArray();

        if (!matchingProcessors.Any())
        {
            return null;
        }

        return matchingProcessors[0];
    }
}

// Individual request processors, you will have many of these...
public class StepA: IProcessor
{
    public bool CanProcess(Request request, Response response)
    {
        // Validate wether this can be processed -- if condition here
        return false;
    }

    public bool Handle(Request request, out Response response)
    {
        response = null;
        return false;
    }
}

你可以把所有的if条件,按照你想要的格式放在它们自己的函数中,返回执行executeThisFunctionInAnyCase()函数。

从OP中的基本示例来看,条件测试和执行可以这样分离;

void InitialSteps()
{
  bool conditionA = executeStepA();
  if (!conditionA)
    return;
  bool conditionB = executeStepB();
  if (!conditionB)
    return;
  bool conditionC = executeStepC();
  if (!conditionC)
    return;
}

然后被这样称呼;

InitialSteps();
executeThisFunctionInAnyCase();

如果c++ 11 lambda是可用的(OP中没有c++ 11标记,但它们可能仍然是一个选项),那么我们可以放弃单独的函数,并将其包装为lambda。

// Capture by reference (variable access may be required)
auto initialSteps = [&]() {
  // any additional code
  bool conditionA = executeStepA();
  if (!conditionA)
    return;
  // any additional code
  bool conditionB = executeStepB();
  if (!conditionB)
    return;
  // any additional code
  bool conditionC = executeStepC();
  if (!conditionC)
    return;
};

initialSteps();
executeThisFunctionInAnyCase();