Sometimes you just have to ask why. Why would you ever produce this monstrosity?
void processMovies(ListmovieList, User user) { if (user.hasFavouriteMovies()) { Movie movie; while (movieList.hasNext()) { movie = movieList.next(); switch (movie.getRating()) { case LOVED_IT: if (movie.hasExplosions()) { doLovedItWithExplosions(movie); } else { doLovedItWithoutExplosions(movie); } break; case HATED_IT: if (movie.hasExplosions()) { doHatedItWithExplosions(movie); } else { doHatedItWithoutExplosions(movie); } break; default; if (movie.hasExplosions()) { doIndifferentItWithExplosions(movie); } else { doIndifferentItWithoutExplosions(movie); } } } } }
There is no good reason to have an if inside a switch. If you have to do a further conditional in the switch than either break it out into a function or get rid of the switch. It makes it unreadable, especially if it is nested inside two other layers of nesting as in the example above. That is too much to handle.
We can refactor this in multiple ways. I prefer the cases of my switch statement to be small so I will break out the logic into separate functions and thus reducing the cyclic complexity of that code. You could also translate the switch statement into an if/else if/else structure as well, but I do not find that to be as elegant.
void doLovedIt(Movie movie) {
if (movie.hasExplosions()) {
doLovedItWithExplosions(movie);
} else {
doLovedItWithoutExplosions(movie);
}
}
/* doHatedIt, doInfferent */
void processMovies(List movieList, User user) {
if (user.hasFavouriteMovies()) {
Movie movie;
while (movieList.hasNext()) {
movie = movieList.next();
switch (movie.getRating()) {
case LOVED_IT:
doLovedIt(movie);
break;
case HATED_IT:
doHatedIt(movie);
break;
break;
default;
doIndifferentIt(movie);
break;
}
}
}
}
I find that to be much more readable, and it is easier to test. The new functions can be unit tested easily since they are isolated, and the processMovies function can be tested easier as well because it no longer have all the extra ifs to execute.