How do I make a block of code that contains a return statement into a function?
If I have a similar block of code that is used in many places but has different functions but contains return statements, how can I reorganize it to make this block a function? For example, let’s say I have an object Mailman
, which contains a valid code (successful/failed/failed reason) and possibly a package for the callee.
In one case, Postman might just pick up the element he’s holding and give it to the callee:
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();
}
But at another he may be resending a letter
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();
}
Only blocks of code that look very similar, I want to break this logic down somewhere, but dealing with different success/failure scenarios makes me sad.
Solution
You already have the answer “half” in your code:
Mailman mailman = requestMailForPerson(person);
Contrast
Mailman mailman = rerouteLetterForPerson(letter, person);
The key point here is that those Mailman class objects that should not be “identical”. Mailman can be an interface, and your method will return a different implementation of it!
Then you just call a method
mailman.doYourJob();
You get the right results; Depends on the underlying implementation code!
In a sense, you are absolutely right, because such internal state switching code has a very bad smell. It violates the Tell Don’t Ask principle. This is the part you really want to avoid: you don’t want to want to externalize that state and let other “external” code make decisions based on that state!