假设我有这样的伪代码:
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语句可以以某种方式使用吗?
假设你不需要单独的条件变量,反转测试并使用else-falthrough作为“ok”路径,将允许你获得更垂直的if/else语句集:
bool failed = false;
// keep going if we don't fail
if (failed = !executeStepA()) {}
else if (failed = !executeStepB()) {}
else if (failed = !executeStepC()) {}
else if (failed = !executeStepD()) {}
runThisFunctionInAnyCase();
省略失败的变量使代码在我看来有点太晦涩了。
在里面声明变量就可以了,不用担心= vs ==。
// keep going if we don't fail
if (bool failA = !executeStepA()) {}
else if (bool failB = !executeStepB()) {}
else if (bool failC = !executeStepC()) {}
else if (bool failD = !executeStepD()) {}
else {
// success !
}
runThisFunctionInAnyCase();
这很模糊,但很紧凑:
// keep going if we don't fail
if (!executeStepA()) {}
else if (!executeStepB()) {}
else if (!executeStepC()) {}
else if (!executeStepD()) {}
else { /* success */ }
runThisFunctionInAnyCase();
对于c++ 11及以上版本,一个很好的方法可能是实现一个类似D的作用域(退出)机制的作用域退出系统。
实现它的一种可能的方法是使用c++ 11 lambdas和一些helper宏:
template<typename F> struct ScopeExit
{
ScopeExit(F f) : fn(f) { }
~ScopeExit()
{
fn();
}
F fn;
};
template<typename F> ScopeExit<F> MakeScopeExit(F f) { return ScopeExit<F>(f); };
#define STR_APPEND2_HELPER(x, y) x##y
#define STR_APPEND2(x, y) STR_APPEND2_HELPER(x, y)
#define SCOPE_EXIT(code)\
auto STR_APPEND2(scope_exit_, __LINE__) = MakeScopeExit([&](){ code })
这将允许你提前从函数返回,并确保你定义的任何清理代码总是在作用域退出时执行:
SCOPE_EXIT(
delete pointerA;
delete pointerB;
close(fileC); );
if (!executeStepA())
return;
if (!executeStepB())
return;
if (!executeStepC())
return;
宏实际上只是装饰。MakeScopeExit()可以直接使用。
一个简单的解决方案是使用一个条件布尔变量,同一个变量可以重复使用,以检查顺序执行的所有步骤的结果:
bool cond = executeStepA();
if(cond) cond = executeStepB();
if(cond) cond = executeStepC();
if(cond) cond = executeStepD();
executeThisFunctionInAnyCase();
并不是说在此之前没有必要这样做:bool cond = true;... 然后后跟if(cond) cond = executeStepA();cond变量可以立即赋值给executeStepA()的结果,因此使代码更短,更易于阅读。
另一个更奇特但有趣的方法是这样的(有些人可能认为这是IOCCC的一个很好的候选,但仍然如此):
!executeStepA() ? 0 :
!executeStepB() ? 0 :
!executeStepC() ? 0 :
!executeStepD() ? 0 : 1 ;
executeThisFunctionInAnyCase();
结果是完全相同的,如果我们做什么OP张贴,即:
if(executeStepA()){
if(executeStepB()){
if(executeStepC()){
if(executeStepD()){
}
}
}
}
executeThisFunctionInAnyCase();
这看起来像一个状态机,这很方便,因为您可以使用状态模式轻松实现它。
在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();