繁体   English   中英

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

[英]Better way to structure/new keyword

前段时间我遇到了以下我很少见过的构造,虽然我比较频繁地使用它。 我通常在检查整个条件列表时使用它,并且它可以防止大量缩进。 基本上它使用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循环的误用,并且实际上是一个解决方案,我认为是非常整洁的,并且是我原本想要找到的。 我猜这个结构可能并不为人所知,因为没有人提到它,人们强烈反对这个?

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

为什么不用这个?

boolean valid = true;

if (!condition1)
    valid = false;

else if (!condition2)
    valid = false;

else if (!condition3)
    valid = false;

if (valid) dosomething();

您可能已经听说过现代编程语言所具有的这些东西,称为函数 ;)不再使用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();

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

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

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

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

不幸的是,只有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();
}
//...

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

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

和..

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

我觉得这个问题

if (condition1 && condition2 && ...) 

很简单,如果有很多条件,它可能会变得难以阅读和编辑,尽管你总是这样写:

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

你怎么样把循环变成一个函数:

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

如果你想保持缩进,这是一种妥协:

boolean valid = true;  // optimistic start

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

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

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

if (valid)
   doSomething();

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

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

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

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

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

bool valid = true;

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

     if (!condition2)
        valid = false;

     if (!condition3)
        valid = false;

}

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

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

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

如何将设置重定位到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;
}

您可以将该代码输出到单独的函数并使用多个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();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM