I am designing a game with multiple levels. I have a setup class that sets up the board based on the argument it receives, which indicates which level it should set up. Here is the class:
public class BoardState {
public BoardState(InitialState state) {
switch (state) {
case EMPTY:
setupEmptyState();
break;
case INTEGRATIONTEST:
setupIntegrationTestState();
break;
case LEVEL_1:
setupLevelOne();
break;
case LEVEL_2:
setupLevelTwo();
break;
default:
throw new Error("Invalid level selection");
}
}
private void setupEmptyState() { }
private void setupIntegrationTestState() { }
private void setupLevelOne() { }
private void setupLevelTwo() { }
}
This works fine, but every time I add a new level I have to add code in three places: The InitialState
enum
which defines the list of accepted states, the switch
statement in the constructor, and the body of the class, where I have to add a method to set up the level in question.
One nice thing that I want to keep is the fact that my GUI automatically populates with a new button for each level I add based on the enum
defining the list of levels.
How can I refactor this code so that there is less overhead associated with adding a new level?
Often when you need to reduce code duplication, an interface arise. This time (based on your comment in OP) it seems you need to add different objects to the board depending on which level you are:
Now,
BoardState
looks like that (no moresetupX()
methods)Since you also specified it is nice for you to have an
enum
to dynamically creates buttons on the GUI, one can combine the best of both world (interface and enum) by implementing the interface in an enum...And that's it basically. If you need to add
LEVEL_3
do it inInitialState
and everything will follow.Going one step further
From here it goes beyond what you requested, feel free to ignore this part if you are not convinced.
As a good practice I would store these configurations only in config files to reduce even more the code duplication and gain in flexibility:
So that when you decide to add a new level you actually only need to know the filename in which the level's configuration is stored.
Going another step further
What you will see there is really tricky and I don't advice you to use it in production code (but it reduces code duplication) !
Here we rely on enum names themselves to find the corresponding correct file. This code works because it is based on the convention that the files are named accordingly to the enum names with the ".level" extension. When you need to add a new level, just add it to the enum and that's it...