2014-09-27 71 views
0

我遇到過這樣一種情況:我有一堆需要按順序初始化的「系統」,如果所有的前進系統都成功初始化,下一個系統只會被初始化。切換語句而不是多重嵌套if - else?

這使我得到了一整套嵌套的if - else語句。這裏有一些可視化的僞代碼。

bool mainInit() { 
    if (!system1Init()) { 
     reportError(); // some error reporting function 
    } 
    else { 
     if (!system2Init()) { 
      reportError(); 
     } 
     else { 
      if (!system3Init()) { 
      // ... and so on 

我發現當你得到幾個關卡時,這看起來就像一團糟。

現在我想用一個switch語句來代替,開始在第一種情況下,通過下降到成功的其他情況下,只要有一個錯誤打破。

bool mainInit() { 

    switch (1) { 
    case 1: 
     if (!system1Init()) { 
      reportError(); 
      break; 
     } 
    case 2: 
     if (!system2Init()) 
      reportError(); 
      break; 
     } 
    // .... 
} 

現在,我更喜歡這個了。我發現讀起來容易多了,特別是有一些體面的評論,但我對編程相當陌生。

所以,我的問題是:怎麼看這不是開關語句是如何傳統上使用(至少從我所看到),是這樣的可以接受的,或將本被認爲是不好的形式?

作爲新的節目,我想不發展太多的壞習慣,可能阻撓,併爲其他程序員在路上事情變得更加困難。

我做了搜索,但大部分我發現曾與替換如果鏈來完成 - else if語句,而不是取代嵌套的。依次

+0

後,所有的if語句中會發生什麼? 'mainInit'返回什麼? – Beta 2014-09-27 21:14:31

+0

如何在失敗時返回「假」或「拋出......」? – 2014-09-27 21:16:48

+0

你不必做'else {if(){'大多數人做'else if(){'。 – Galik 2014-09-27 21:39:22

回答

3

參考所有的系統在一個陣列,例如一個std::vector<mySystem*>,和環就過去了,在折斷第一故障。通過這種方式,即使對於500多個系統,您的整個代碼也會減少到少於5行代碼。

建議的交換機黑客是一個邪惡的例子XY problem solving:你真正的問題是你沒有系統數組,並且正在使用命名變量,從而消除了所有選項以更靈活地使用所有系統,如在循環。

+0

我在我的問題的代碼中犯了一個錯誤,我沒有直接處理系統對象(我甚至不確定是否有它下面的所有對象)我正在初始化部分ac庫以供使用。我道歉。我想我真的不明白我應該問什麼。那麼我會使用一個函數向量嗎? – liquidhand 2014-09-27 21:55:25

+0

我不認爲這個問題是一個XY問題,因爲用戶首先提出正確的問題,並給出了他可以做什麼的可能答案。 XY是當用戶只問「我應該做一個開關」而沒有先說明真正的問題。 – 2014-09-27 22:06:20

0

假設所有system#Init()調用在編譯時已知的,你可以很容易的把它們放在一個表,然後遍歷該表。

typedef (*system_init)(void); 

system_init initialization_functions[] = 
{ 
    system1Init, 
    system2Init, 
    system3Init, 
     ... 
    systemNInit 
}; 

bool mainInit() 
{ 
    for(size_t idx(0); idx < sizeof(initialization_functions)/sizeof(initialization_functions[0]); ++idx) 
    { 
     if(!initialization_functions[idx]()) 
     { 
      ReportError(); 
      return false; 
     } 
    } 
    return true; 
} 

然而,現有的代碼看起來不正確,因爲第一mainInit()只要求system1Init(),然後退出。可能不是你想要的東西。

if(!system1Init()) 
{ 
    ReportError(); 
    return false; 
} 
// if you add an else, the system2Init() does not get called 
// even if system1Init() succeeds 
if(!system2Init()) 
{ 
    ReportError(); 
    return false; 
} 
[...] 
return true; 

切換器會回答您的問題嗎?不像它寫的那樣。也就是說,如果你想用計數器調用mainInit()函數,它可能很有用。 Drupal使用這一機制:

bool mainInit(int idx) 
{ 
    bool r(true); 
    switch(idx) 
    { 
    case 1: 
     r = system1Init(); 
     break; 

    case 2: 
     r = system2Init(); 
     break; 

    [...] 
    } 
    if(!r) 
    { 
     ReportError(); 
    } 
    return r 
} 

注意到,該表機制的工作方式與開關一樣。只要所有的代碼在systemNInit()功能發現(應該是),開關不添加任何東西,所以你可以做這樣的事情太:

bool mainInit(int idx) 
{ 
    if(idx < 0 || idx >= sizeof(initialization_functions)/sizeof(initialization_functions[0])) 
    { 
     throw std::range_error("index out of bounds"); 
    } 
    if(!initialization_functions[idx]()) 
    { 
     ReportError(); 
     return false; 
    } 
    return true; 
} 

調用mainInit()使用索引可以如果有幫助你想「去初始化」正確:

int main() 
{ 
    for(size_t idx(0); idx < ...; ++idx) 
    { 
     if(!mainInit(idx)) 
     { 
      while(idx > 0) 
      { 
       --idx; 
       mainDeinit(idx); 
      } 
      exit(1); 
     } 
    } 
    ...app do something here... 
} 
0

有清楚的錯誤消息使用自定義異常,並添加周圍的代碼main()的try-catch-報告,死亡。例外情況是通過使「不良路徑」隱含,使您的案例更加美觀。

void initX() { ...; throw std::invalid_argument_exception("..."); } 

int main() { 
    try { 
     init1(); init2(); ... run(); 
     return 0; 
    } catch (std::exception const& e) { 
     log(e.what()); exit 42; 
    } 
} 
0

我會做這種方式:

bool mainInit() { 
    if (!system1Init()) { 
    return(false); 
    } 

    if (!system2Init()) { 
    return(false); 
    } 

    if (!system3Init()) { 
    return(false); 
    } 

    //...     

    return(true); 
} 

//... 

if(!mainInit()) { 
    reportError(); 
}