I am currently implementing a simulation in Java that requires an input of about 30 different parameters. Eventually, I want to be able to read these parameters from a file and also from a GUI, but I am just focusing on the file input for now. My simulation requires parameters that are of different types: Strings, ints and doubles and I currently have them as fields for the simulation e.g.
private String simName;
private int initialPopulationSize;
private double replacementRate;
Because these parameters are not all the same type I can’t store them in an array and I have to read each one in separately using the same kind of code about 30 times. An example for three parameters:
//scanner set up and reading each line, looking for "(key)=(param)" regex matches
//if statement to check each param name against the key matched in file. Store param in that field if the name matches.
String key = m.group(1);
if (key.equals(PKEY_SIM_NAME)) {
if (simNameSet) {
throw new IllegalStateException("multiple values for simulation name");
}
this.simName = m.group(2);
simNameSet = true;
} else if (key.equals(PKEY_INITIAL_SIZE)) {
if (initialSizeSet) {
throw new IllegalStateException("multiple values for initial population size");
}
this.initialPopulationSize = Integer.parseInt(m.group(2));
initialPopulationSize = true;
} else if (key.equals(PKEY_MUT_REPLACEMENT)) {
if (replacementRateSet) {
throw new IllegalStateException("multiple values for replacement rate");
}
this.replacementRate = Double.parseDouble(m.group(2));
replacementRateSet = true;
}
//Add nauseum for each parameter.....
So I currently have a long and unweildly method for reading in parameters, and I will likely need to do the same again for reading from gui.
The best alternative I have thought of is to read everything into String fields first. That way I can write a simple few lines for reading in using a Map. Something like this (untested code):
//This time with a paramMap<String, String>, scanner set up as before
if (!paramMap.containsKey(key)) {
paramMap.put(key, m.group(2));
}
else{
throw new IllegalStateException("multiple values for initial population size");
}
However, this will be inconvenient when it comes to using these parameters from the Map, since I will have to cast the non-String params whenever and wherever I want to use them.
At this point I feel like this is my best approach. I want to know if anyone a little more experienced can come up with a better strategy for dealing with this kind of situation before I move on.
You can define a base Parameter class or interface like:
and a class for each type of parameter you want to have, e.g.
IntParameter,DoubleParameter,StringParameter. Here’s a sketch of anIntParameter:Then you can store your parameters in a
Map<String, Parameter>and populate from various sources, like command-line options or properties.A more type-safe but convoluted solution can be achieved if you don’t store the value in parameter objects, but make parameters static objects that are used to access their values.
This is illustrated on the following example:
This allows you to access parameter in a type safe manner:
The solution can be extended to other types.