簡體   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