2017-02-09 88 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; 
      } 
     });