更好的结构/新关键字方式

时间:2010-12-14 12:27:17

标签: java c++

前段时间我遇到了以下很少见过的构造,虽然我比较频繁地使用它。我通常在检查整个条件列表时使用它,并且它可以防止大量缩进。基本上它使用for循环来提供一种结构化的goto。我的问题首先是否有更好的方法来构建它,其次是人们是否喜欢它,第三是java / c ++中的新关键字(例如unit {})是否只会导致中断退出到单元的末尾有用而且更清晰。

ps我意识到它正在脱离无限循环,但我认为我对此的偏执意味着它从未发生过。

编辑:我已经为其他条件添加了一些设置代码,以尝试用链接来解决问题

boolean valid = false;

// this loop never loops
for (;;)
{
    if (!condition1)
        break;

    condition2.setup();

    if (!condition2)
        break;

    condition3.setup();

    if (!condition3)
        break;

    valid = true;
    break;
}

if (valid) dosomething();

编辑:

我刚刚发现,实际上有一种方法可以在java中构造它而不会滥用循环等,并且想知道这是否会同样不受欢迎,尽管我想我已经错过了这个。

重组后的代码看起来像这样。

boolean valid = false;

breakout:
{
    if (!condition1)
        break breakout;

    condition2.setup();

    if (!condition2)
        break breakout;

    condition3.setup();

    if (!condition3)
        break breakout;

    valid = true;
}

if (valid) dosomething();

现在,这消除了导致很多抱怨的for循环的误用,实际上我认为这是一个非常简洁的解决方案,而且是我原本想要找到的。 我猜这个结构可能并不为人所知,因为没人提到它,人们强烈反对这个结构?

12 个答案:

答案 0 :(得分:16)

这个循环是违反直觉的,在代码审查中会受到质疑:“如果你总是在第一次迭代中破解,为什么还需要循环?”

为什么不使用它?

boolean valid = true;

if (!condition1)
    valid = false;

else if (!condition2)
    valid = false;

else if (!condition3)
    valid = false;

if (valid) dosomething();

答案 1 :(得分:7)

您可能听说过现代编程语言所具有的这些东西,称为 functions ;) 不再使用goto的一个主要原因是我们现在可以将代码分解为单独的函数,而是调用它们。

解决问题的一种方法是将代码放在一个单独的函数中,而返回而不是从伪循环中断开:

void safedosomething() {
    if (!condition1)
        return;

    condition2.setup();

    if (!condition2)
        return;

    condition3.setup();

    if (!condition3)
        return;

    dosomething();
}

或编写辅助函数(如bool checkcondition1() { condition1.setup(); return condition1; }),设置然后测试条件,并使用布尔标志:

bool valid = true;

if (!checkcondition1())
    valid = false;

if (!checkcondition2())
    valid = false;

if (!checkcondition3())
    valid = false;

if (!checkcondition4())
    valid = false;

if (valid) dosomething();

或更简洁一点:

bool valid = true;

valid &&= checkcondition1();
valid &&= checkcondition2();
valid &&= checkcondition3();
valid &&= checkcondition4();

if (valid) dosomething();

或只是

if (checkcondition1()
  && checkcondition2()
  && checkcondition3()
  && checkcondition4())
    dosomething();

有很多方法可以表达这一点,没有违反直觉的循环 - 不要循环。

答案 2 :(得分:4)

这种结构的原因是因为goto是编程中的脏词。但是让我们面对它,你正在有效地使用循环结构来做同样的事情。我对此的看法要么是诚实的,要么使用goto或重构代码。

答案 3 :(得分:3)

我不认为这是最可读的方式。链式if - else if看起来好多了。但是如果你想坚持下去并且不想接近无限循环,你可以这样做:

do
{
    if (...)
        break;
    ...
} while (false);

答案 4 :(得分:3)

不幸的是,

仅限C ++:

if ( condition1
     && (condition2.setup(), condition2)
     && (condition3.setup(), condition3) )
{
    dosomething();
}

对于java兼容的东西(但我还在编写C ++!),我会回过头来讨论这个问题。 (显然,某些上下文可能需要传递到CheckConditions()。)

bool CheckConditions()
{
    if (!condition1)
        return false;

    condition2.setup();

    if (!condition2)
        return false;

    condition3.setup();

    if (!condition3)
        return false;

    return true;
}

//...
if (CheckConditions())
{
    dosomething();
}
//...

答案 5 :(得分:2)

您似乎担心评估条件2需要一些设置,而您不知道将它放在何处。将其重构为一个单独的布尔方法,然后使用几乎所有人在这里描述的方式。例如:

if (checkCondition1() && checkCondition2(someInput) && checkCondition3()) {
    doSomething();
}

和..

private boolean checkCondition2(Object someInput) {
    //setup condition 2
    return condition2;
}

答案 6 :(得分:1)

我认为

的问题
if (condition1 && condition2 && ...) 

只是在有很多条件的情况下很难读取和编辑,尽管你总是这样写:

if ( condition1 &&
     condition2 &&
     condition3 ... )
    doStuff();

如何将循环转换为函数:

bool all()
{
    if (!condition1) return false;
    if (!condition2) return false;
    if (!condition3) return false;      
    ....
    return true;
}

答案 7 :(得分:1)

如果你想保持缩进的话,这就是妥协:

boolean valid = true;  // optimistic start

if (!valid || !condition1)
   valid = false;

if (!valid || !condition2)
   valid = false;

if (!valid || !condition3)
   valid = false;

if (valid)
   doSomething();

第一个!valid语句中的if是超级流畅的,但不会造成伤害,可以保留以便于阅读。 else/if对我来说更优雅,但这只是一种观点。

但我真的不会(ab-)使用for循环,我从来没有找到一种廉价的方法来实现伪goto。总有一个更好的解决方案。

答案 8 :(得分:0)

如果在循环结束时有break语句,我不确定为什么需要循环。不管情况如何,你只是迭代一次吗?

无论如何,你通常会在SO上找到两个不同的意见,一个是断言不应该被使用,一个是它取决于情况。

我倾向于使用后一组,但循环的工作方式使用多余的break语句。我宁愿构建这样的循环:

bool valid = true;

for(... ; .... && valid == true ; ....)
{
     if (!condition1)
        valid = false;

     if (!condition2)
        valid = false;

     if (!condition3)
        valid = false;

}

这允许我认为更优雅的循环退出。

答案 9 :(得分:0)

拥有如此长的if语句很可能是错误的编码。
它使测试变得非常困难,并且很可能是代码味道。

如果可能的话,你应该重构以利用多态性。

答案 10 :(得分:0)

如何将设置重定位到Condition类的operator bool?这使得它更具可读性并隐藏了机制。

class Condition
{
    bool _isSet;
public:
    Condition() : _isSet(false) {
    }
    void setup() {
        _isSet = true;
    }
    operator bool () {
        if (!_isSet) {
            setup();
        }
        return rand() & 1;
    }
};

void doSomething()
{
}

int _tmain(int argc, _TCHAR* argv[])
{
    Condition cond1, cond2, cond3;
    if (cond1 && cond2 && cond3) {
        doSomething();
    }
    return 0;
}

答案 11 :(得分:0)

您可以将该代码输出到单独的函数并使用多个return语句。无论如何,您可能需要将长if语句列表重构为单独的函数。

bool isValid()
{
    if (!condition1)
        return false;

    condition2.setup();

    if (!condition2)
        return false;

    condition3.setup();

    if (!condition3)
        return false;

    return true;
}

然后你可以在你的代码中使用它:

if (isValid()) dosomething();