2017-02-09 74 views
3

如果我有一個類似的代碼塊用於許多功能不同,但包含返回語句的地方,我如何重構它以使此塊變成函數?例如,假設我有一個對象Mailman,其中包含一個有效性代碼(成功/失敗/失敗的原因),也可能是一個給被調用者的包。如何製作一個包含返回語句的代碼塊?

在一種情況下,郵遞員可能只是抓住他的項目多數民衆贊成舉行,它給被叫方:

Mailman mailman = requestMailForPerson(person); 

switch(mailman.getStatus()){ 
    case SUCCESS: 
     Mail mail = (Mail)mailman.getHeldItem(); 
     return Response.ok().entity(mail).build(); 
    case PERSON_DOESNT_EXIST: 
     return Response.status(Response.status.BAD_REQUEST).build(); 
    case MAIL_SERVICE_FAILED_SOMEWHERE: 
     return Response.status(Response.status.INTERNAL_SERVER_ERROR).build(); 
} 

但在另一種他可能會重新路由信

Mailman mailman = rerouteLetterForPerson(letter, person); 

switch(mailman.getStatus()){ 
    case SUCCESS: 
     Letter letter = (Letter)mailman.getHeldItem(); 
     if(distance(letter.address, currentLocation) > 50){ 
      sendToNextoffice(letter); 
      return Response.ok.entity("in transit").build(); 
     }else{ 
      return Response.ok().entity(letter).build(); 
     } 

    case PERSON_DOESNT_EXIST: 
     return Response.status(Response.status.BAD_REQUEST).build(); 
    case MAIL_SERVICE_FAILED_SOMEWHERE: 
     return Response.status(Response.status.INTERNAL_SERVER_ERROR).build(); 
} 

只是有塊的代碼看起來非常相似,我想在某處展開這種邏輯,但處理不同的成功/失敗場景給我一個很難的時間。

+0

是否有一些'()'缺少'響應ok'後'。 ok.entity(「在途」)? –

回答

3

你已經在你的代碼你的答案的 「半壁江山」:

Mailman mailman = requestMailForPerson(person); 

Mailman mailman = rerouteLetterForPerson(letter, person); 

這裏的關鍵點是:那些不應該是「相同的」郵差類對象。郵差可能是一個接口和您的方法返回不同的實現!

然後你只需要調用像

mailman.doYourJob(); 

的方法,你會得到正確的結果;取決於底層的實現代碼!

你是在這個意義上,這種交換機上的內部狀態代碼有一個非常壞的氣味完全正確的。它違反了Tell Don't Ask原則。這是你真正想要避免的部分:你做不是externalise那個狀態,並且有其他的「外部」代碼根據它做出決定!

0

只需要添加一個標誌,你的函數,指出是否要檢查的距離:

bool checkStatus(Mailman& toCheck, bool checkDistance) 
{ 
    switch(toCheck.getStatus()){ 
    case SUCCESS: 
     Letter letter = (Letter)mailman.getHeldItem(); 
     if(checkDistance && distance(letter.address, currentLocation) > 50){ 
      sendToNextoffice(letter); 
      return Response.ok.entity("in transit").build(); 
     }else{ 
      return Response.ok().entity(letter).build(); 
     } 

     case PERSON_DOESNT_EXIST: 
      return Response.status(Response.status.BAD_REQUEST).build(); 
     case MAIL_SERVICE_FAILED_SOMEWHERE: 
      return Response.status(Response.status.INTERNAL_SERVER_ERROR).build(); 
    } 

} 

然後,你必須用例1:

Mailman mailman = requestMailForPerson(person); 
return checkStatus(mailman, false); 

和用例2 :

Mailman mailman = rerouteLetterForPerson(letter, person); 
return checkStatus(mailman, true); 
+0

這將適用於OP,但不會很好地擴展。 –

+1

大多數情況下,這些標誌都表示「OO設計」......做錯了或完全失蹤。像這兒。而使用** booleans **更糟糕。但是使用枚舉代替也不會好得多。 – GhostCat

+0

@GhostCat是的我以爲我們現在只是有一個糟糕的設計。我們有我們所說的「Payload」來處理錯誤情況(或者返回所請求的對象),這或多或少是我們的Hacks版本的Exceptions(當時團隊中沒有人想因爲整體而拋出異常「對於例外情況只有「辯論),但我認爲我將不得不用例外代替」Payload「,因爲現在代碼庫看起來很混亂和愚蠢。 – GuitarStrum

0

如果要減少代碼重複並使代碼更具可讀性,回調函數可能是一個可行的選項。只是「告訴」方法在SUCCESS案件中要做什麼。

public process(Mailman mailman, Function<Mailman, Object> onSuccess) { 
    switch (mailman.getStatus()) { 
    case SUCCESS: 
     return Response.ok().entity(onSuccess.apply(mailman)).build(); 
    case PERSON_DOESNT_EXIST: 
     return Response.status(Response.status.BAD_REQUEST).build(); 
    case MAIL_SERVICE_FAILED_SOMEWHERE: 
     return Response.status(Response.status.INTERNAL_SERVER_ERROR).build(); 
    } 
}  

當調用功能,只是在回調傳遞作爲一個匿名函數,甚至只是一個方法參考:

process(requestMailForPerson(person), Mailman::getHeldItem); 

process(rerouteLetterForPerson(theLetter, person), 
     mailman -> { 
      Letter letter = (Letter) mailman.getHeldItem(); 
      if (distance(letter.address, currentLocation) > 50){ 
       sendToNextoffice(letter); 
       return "in transit"; 
      } else { 
       return letter; 
      } 
     }); 
相關問題