Managing constructors with many parameters in Java
JavaJava Problem Overview
In some of our projects, there's an class hierarchy that adds more parameters as it goes down the chain. At the bottom, some of the classes can have up to 30 parameters, 28 of which are just being passed into the super constructor.
I'll acknowledge that using automated DI through something like Guice would be nice, but because of some technical reasons, these specific projects are constrained to Java.
A convention of organizing the arguments alphabetically by type doesn't work because if a type is refactored (the Circle you were passing in for argument 2 is now a Shape) it can suddenly be out of order.
This question might be to specific and fraught with "If that's your problem, you're doing it wrong at a design level" criticisms, but I'm just looking for any viewpoints.
Java Solutions
Solution 1 - Java
The Builder Design Pattern might help. Consider the following example
public class StudentBuilder
{
private String _name;
private int _age = 14; // this has a default
private String _motto = ""; // most students don't have one
public StudentBuilder() { }
public Student buildStudent()
{
return new Student(_name, _age, _motto);
}
public StudentBuilder name(String _name)
{
this._name = _name;
return this;
}
public StudentBuilder age(int _age)
{
this._age = _age;
return this;
}
public StudentBuilder motto(String _motto)
{
this._motto = _motto;
return this;
}
}
This lets us write code like
Student s1 = new StudentBuilder().name("Eli").buildStudent();
Student s2 = new StudentBuilder()
.name("Spicoli")
.age(16)
.motto("Aloha, Mr Hand")
.buildStudent();
If we leave off a required field (presumably name is required) then we can have the Student constructor throw an exception. And it lets us have default/optional arguments without needing to keep track of any kind of argument order, since any order of those calls will work equally well.
Solution 2 - Java
Can you encapsulate related parameters inside an object?
e.g., if parameters are like
MyClass(String house, String street, String town, String postcode, String country, int foo, double bar) {
super(String house, String street, String town, String postcode, String country);
this.foo = foo;
this.bar = bar;
then you could instead have:
MyClass(Address homeAddress, int foo, double bar) {
super(homeAddress);
this.foo = foo;
this.bar = bar;
}
Solution 3 - Java
What you probably want to do is have a Builder class. Then you would do something like this:
MyObject obj = new MyObjectBuilder().setXxx(myXxx)
.setYyy(myYyy)
.setZzz(myZzz)
// ... etc.
.build();
See page 8 and following of this Josh Bloch presentation (PDF), or this review of Effective Java
Solution 4 - Java
Well, using the builder pattern might be one solution.
But once you come to 20 to 30 parameters, I would guess that there is a high relationship between the parameters. So (as suggested) wrapping them into logically sane data-objects probably makes the most sense. This way the data object can already check the validity of constraints between the parameters.
For all of my projects in the past, once I came to the point to have too many parameters (and that was 8 not 28!) I was able to sanitize the code by creating a better datamodel.
Solution 5 - Java
The best solution is not having too much parameters in the constructor. Only parameters really needed in constructor, are params that are need to correctly initialize the object. You can have constructors with multiple parameters, but also have a constructor with only the minimum parameters. The additional constructors call this simple constructor and after that setters to set the other params. This way you can avoid the chain-problem with more and more params, but also have some convenience-constructors.
Solution 6 - Java
As you are constrained to Java 1.4, if you want DI then Spring would be a very decent option. DI is only helpful in places where the constructor parameters are services or something that does not vary during runtime.
If you have all of those different constructors due to the fact that you want variable options on how to construct an object, you should seriously consider using the Builder pattern.
Solution 7 - Java
I can really recommend using Immutables or POJOBuilder when using the builder pattern.
Solution 8 - Java
Refactoring to reduce the number of parameters and depth of you inheritance hierarchy is pretty much all I can think of because, nothing is really going to help keep 20-something parameters straight. You're just going to have to every single call while looking at the documentation.
One thing you could do, is to group some logically grouped parameters into their own higher level object, but that has it's own problems.