Reputation: 371
I am in the process of making an application which is meant to be a personal pet project of mine, designed around comparing two vehicles against 1 another from a computer game I play the vehicles have a bunch of stats such as speed, healthpoints, turret traversal etc. and I want to create a small app that will highlight the differences between the vehicles, however i have come to a stumbling block where the arguments taken for the constructors for each vehicles are huge and difficult to read
Here is an example of object creation with the given constructor:
HeavyTank T110E5 = new HeavyTank("T110E5", 2200,54.56d, 875, 37, 30, 254,76,38, 203,127,70,300, 202, 6,32, 400,745,10);
I am sure you would guess that this application I am making, is a tank comparer based off World of tanks, where I am hard coding the tank stats, but as you can see, the arguments taken are difficult to read, making it difficult to create new objects without getting confused. Each tank has different stats so this means I would have to hard code close to 100+ tanks individually. If someone here has a solution of reducing the mess, or recommendations I am willing to listen.
I would also like to reinstate a point I made up at the top, this application is not for commercial purposes and is purely just a pet personal project of mine.
Upvotes: 0
Views: 208
Reputation: 45
My suggestion would be to create an object to hold these types with a specific parameter list upon initialization. You can divide up that object based on what types go together logically. Then you'll only need two or three constructors with five parameters each. For example:
HeavyTank T110E5 = new HeavyTank("T110E5", 2200,54.56d, 875, 37, 30, 254,76,38, 203,127,70,300, 202, 6,32, 400,745,10);
would become:
StatObject1 stat1 = new StatObject1(2200, 54.56d);
StatObject2 stat2 = new StatObject2(875, 37, 30);
StatObject3 stat3 = new StatObject3(254, 76, 38);
...
HeavyTank T110E5 = new HeavyTank("T110E5", stat1, stat2, stat3, ...);
or however that works out logically for your system. The benefit of this is that you can apply this to any other tank you create, and can create modifiers in every StatObject class specific to that data.
Upvotes: 0
Reputation: 4608
You have three reasonable options that I see:
1) Use the standard contructor("string", value, "string", value,...)
format.
This is likely more effort than you will want to put into this program.
2) Use a constructor()
method and then setPropertyName(value)
methods for each property.
This will allow you to easily add them, but you still need to do it by hand.
3) Read the data in from a file. Setup the file using columns with names (to avoid just moving the "I forgot what value comes next" problem to a different place) This should be the best.
Upvotes: 0
Reputation: 1
I recommend implementing a Standard Constructor without any Parameters. Setters and Getters can be generated via eclipse. This helps keeping a look at all and adding or removing members. The next thing you should do is to write all your vehicle stuff in a XML file. The tags help you with the vehicle names, values etc. Also adding and removing vehicles will be easier. You can access XML files via JDOM. Just read the vehicle tags and call the setter methods with the values from the XML file. This can be done with a loop.
In the end, the only thing you have to take care of is your vehicle XML file.
Feel free to ask if there are any questions.
Upvotes: 0
Reputation: 95528
If you have a mix of required and optional arguments (with sensible defaults), you can use the builder pattern. An example from Effective Java:
public class NutritionalFacts {
private int sodium;
private int fat;
private int carbo;
public static class Builder {
private int sodium;
private int fat;
private int carbo;
public Builder(int s) {
this.sodium = s;
}
public Builder fat(int f) {
this.fat = f;
return this;
}
public Builder carbo(int c) {
this.carbo = c;
return this;
}
public NutritionalFacts build() {
return new NutritionalFacts(this);
}
}
private NutritionalFacts(Builder b) {
this.sodium = b.sodium;
this.fat = b.fat;
this.carbo = b.carbo;
}
}
Then you can do things like:
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8). calories(100).sodium(35).carbohydrate(27).build();
The first two arguments are required (240 and 8). The other attributes are optional and can be supplied through aptly-named methods.
You can still use the builder pattern if you have a large number of required parameters; you can check that they have been set in the build()
method.
Upvotes: 0
Reputation: 20159
This sounds like a perfect use case for the builder pattern.
There are lots of good examples on how to implement this. Here's how Google uses it in the CacheBuilder
class of Guava:
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.removalListener(MY_LISTENER)
.build(
new CacheLoader<Key, Graph>() {
public Graph load(Key key) throws AnyException {
return createExpensiveGraph(key);
}
});
This particular example even uses method chaining, but that's less important. The main feature is that newBuilder()
sets some default parameters which you can then selectively adjust with one or more method calls. Finally, you call build()
to actually create the instance (and calling the actual constructor with the long list of parameters).
Upvotes: 2
Reputation: 23001
I would suggest storing your tank data in a simple file format, for example a CSV file with one line per tank. Then your tank object can take something like an InputStream
as a parameter and stream in the tank details from the file.
And if you use a CSV file you can just use a typical spreadsheet program to edit your tank details quite easily.
Upvotes: 3
Reputation: 16392
You might consider putting that information in a properties file that you could then easily edit. Your constructor would then take the name of the properties file and have the additional job of enforcing completeness and validation. While I still favor strongly-typed constructors, a property file approach might be easier to use in the long run.
Upvotes: 0
Reputation: 109567
Use a fluent interface. Though generally used outside the ccnstructor, why not partly inside.
Upvotes: 0
Reputation: 5866
JavaDoc + good IDE will help you figure out which arguments you need to provide.
Otherwise, you could wrap the arguments in a single object and pass that to the constructor. An overloaded constructor would work well, because you could unpack the arguments and pass it to the original.
If you know the arguments in advance, you would always put them in a Properties file and read them using java.util.Properties
.
Upvotes: 0