In my application, I need to allow the user to store variables. Variables can only be of specific types, but I effectively handle all variables the same way no matter the type. I would also like to avoid any casting. Therefore, I have several HashMap
s for each variable type, which is causing lots of duplicated code. Is there a way to simplify my class?
public class VariableSet {
private final Map<String, PlayerVariable> players;
private final Map<String, NumberVariable> numbers;
private final Set<String> notRemovable;
private final Set<String> usedVariableNames;
public VariableSet(){
players = new HashMap<String, PlayerVariable>();
numbers = new HashMap<String, NumberVariable>();
notRemovable = new HashSet<String>();
usedVariableNames = new HashSet<String>();
addVariable("Current Player", new PlayerVariable(), players, false);
}
public PlayerVariable addPlayer(String variableName){
PlayerVariable var = new PlayerVariable();
addVariable(variableName, var, players, true);
return var;
}
public NumberVariable addNumber(String variableName){
NumberVariable var = new NumberVariable();
addVariable(variableName, var, numbers, true);
return var;
}
private <T extends Variable<?>> void addVariable(String variableName, T variable, Map<String, T> map, boolean removable){
if (usedVariableNames.contains(variableName)){
throw new VariableExistsException();
}
usedVariableNames.add(variableName);
map.put(variableName, variable);
if (!removable){
notRemovable.add(variableName);
}
}
public void removeNumber(String variableName){
removeVariable(variableName, numbers);
}
public void removePlayer(String variableName){
removeVariable(variableName, players);
}
private <T extends Variable<?>> void removeVariable(String variableName, Map<String, T> map){
if (notRemovable.contains(variableName)){
throw new VariableNotRemovableException();
}
usedVariableNames.remove(variableName);
map.remove(variableName);
}
public boolean hasPlayerVariable(String variableName){
return players.containsKey(variableName);
}
public boolean hasNumberVariable(String variableName){
return numbers.containsKey(variableName);
}
public Set<String> getVariableNames(){
return usedVariableNames;
}
public void setPlayer(String variableName, PlayerVariable player){
players.put(variableName, player);
}
public void setNumber(String variableName, NumberVariable number){
numbers.put(variableName, number);
}
}
All variables extend the same abstract class, so using generics is probably the preferred method, but I can't figure out a way to create a data structure that automatically picks the correct variable type without casting.