如果我有一个类似的代码块,该代码块在许多具有不同功能的地方使用,但包含返回语句,我如何重组它以使该块成为函数?例如,假设我有一个对象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();
}
只有看起来非常相似的代码块,我想在某个地方打破这个逻辑,但处理不同的成功/失败场景让我很难。
你的代码中已经有"一半"的答案:
Mailman mailman = requestMailForPerson(person);
与。
Mailman mailman = rerouteLetterForPerson(letter, person);
这里的关键点是:这些不应该是"相同"的 Mailman 类对象。Mailman 可能是一个接口,您的方法返回不同的实现!
然后你只需调用一个方法,如
mailman.doYourJob();
你会得到正确的结果;这取决于底层的实现代码!
您完全正确,因为这种内部状态代码的开关具有非常难闻的气味。它违反了"告诉不问"原则。这是你真正想要避免的部分:你不想将这种状态外部化,并让其他">外部"代码基于此做出决策!
你可以在函数中添加一个标志,说明是否检查距离:
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);
如果要减少代码重复并使代码更具可读性,回调函数可能是一个可行的选择。只需"告诉"方法在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;
}
});