I used to write a collection of constructors when a class could be instantiated in a variety of ways. An important amount of time was spent selecting sensible combinations of constructor arguments to make them easy to use and as readable as possible.
Recently however, I started to work differently since I noticed that complex constructors always end up becoming mysterious. Without looking at the javadocs it's often difficult to understand what each argument stands for.
Consider this example class:
public class Constraint
{
private String mName = null;
private boolean mNotNull = false;
private boolean mNotEmpty = false;
public Constraint(String name, boolean notNull, boolean notEmpty)
{
mName = name;
mNotNull = notNull;
mNotEmpty = notEmpty;
}
}
One would create an instance of Constraint like this:
Constraint constraint = new Constraint("name", true, false);
When you re-read this statement afterwards, you immediately start to wonder which properties the true and false relate to. Was is first notNull and then notEmpty, or was it the other way around?
Now consider this alternative implementation:
public class Constraint
{
private String mName = null;
private boolean mNotNull = false;
private boolean mNotEmpty = false;
public Constraint(String name)
{
mName = name;
}
public Constraint notNull(boolean state)
{
mNotNull = state;
return this;
}
public Constraint notEmpty(boolean state)
{
mNotEmpty = state;
return this;
}
}
To create a instance of Constraint you would now do:
Constraint constraint = new Constraint("name").notNull(true).notEmpty(false);
This is immediately readable without any doubt or confusion. You also don't lose the benefit of being able to instantiate and setup an instance in one line.
Therefore, I now try to create as little constructors as possible. Just the bare minimum is needed to ensure that each instance receives enough information to be initialized in a usable state. All the other optional setup behaviour can be achieved through chainable setters.
You might wonder why I didn't simply change the return type of a regular setter from void to the class type. This is because the javabean spec mandates a void return type on setters. If you don't respect this, the setter will not be found through bean introspection.