假设我有这样的伪代码:
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语句可以以某种方式使用吗?
另一种解决方案是通过宏hack定义习语。
#define block for(int block = 0; !block; block++)
现在,“block”可以用break退出,与for(;;)和while()循环的方式相同。例子:
int main(void) {
block {
if (conditionA) {
// Do stuff A...
break;
}
if (conditionB) {
// Do stuff B...
break;
}
if (conditionC) {
// Do stuff C...
break;
}
else {
// Do default stuff...
}
} /* End of "block" statement */
/* ---> The "break" sentences jump here */
return 0;
}
尽管使用了“for(;;)”结构,但“block”语句只执行了一次。
这些“块”可以用断句退出。
因此,if else if else if…避免使用句子。
最多,最后一个else可以挂在“块”的末尾,以处理“默认”情况。
该技术旨在避免典型的和丑陋的做{…} while(0)方法。
在宏块中,它定义了一个同样名为block的变量,该变量以这样一种方式定义,即恰好执行了一次for迭代。根据宏的替换规则,宏块定义中的标识符块不会被递归替换,因此block成为程序员无法访问的标识符,但在内部可以很好地控制for(;;)循环的“隐藏”。
此外:这些“块”可以嵌套,因为隐藏变量int块将有不同的作用域。
你可以把所有的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();
在阅读了所有的答案之后,我想提供一种新的方法,它在适当的情况下可能非常清晰易读:状态模式。
如果你将所有的方法(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语句或类似语句中,它们应该独立存在!