如何将包含return语句的代码块放入函数中?

时间:2017-02-09 12:10:36

标签: java function design-patterns

如果我有一个类似的代码块,它在很多地方使用,但功能不同但包含return语句,我该如何重构它以使这个块成为一个函数?例如,假设我有一个对象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();
}

只有一些代码块看起来非常相似,我想在某个地方突破这种逻辑,但处理不同的成功/失败场景给我带来了困难。

3 个答案:

答案 0 :(得分:3)

你已经有了#34;一半"您的代码中的答案:

Mailman mailman = requestMailForPerson(person);

VS。

Mailman mailman = rerouteLetterForPerson(letter, person);

这里的关键点是:那些不应该是"相同" Mailman类对象。 Mailman可以是一个接口,你的方法会返回不同的实现!

然后你只需要调用类似

的方法
mailman.doYourJob();

你得到了正确的结果;取决于底层实现代码!

在内部状态代码的开关具有非常错误气味的意义上,您完全正确。它违反了Tell Don't Ask原则。这是您真正想要避免的部分:您希望外化该状态,并拥有其他"外部"代码根据这个做出决定!

答案 1 :(得分: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);

答案 2 :(得分: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;
            }
        });