Chapter 58. Minimal Constructors
Steve Freeman
A pattern I regularly see is significant work done in the constructor: take in a set of arguments and convert them into values for the fields. It often looks like this:
public class Thing {
private final Fixed fixed;
private Details details;
private NotFixed notFixed;
// more fields
public Thing(Fixed fixed,
Dependencies dependencies,
OtherStuff otherStuff) {
this.fixed = fixed;
setup(dependencies, otherStuff);
}
}
I assume that setup initializes the remaining fields based on dependencies and otherStuff, but it’s not clear to me from the constructor signature exactly what values are necessary to create a new instance. It’s also not obvious which fields can change during the life of the object, as they cannot be made final unless they’re initialized in a constructor. Finally, this class is harder to unit test than it should be because instantiating it requires creating the right structure in the arguments to be passed to setup.
Worse, I occasionally used to see constructors like this:
public class Thing {
private Weather currentWeather;
public Thing(String weatherServiceHost) {
currentWeather = getWeatherFromHost(weatherServiceHost);
}
}
which requires an internet connection and a service to create an instance. Thankfully, this is now rare.
All of this was done with the best of intentions to make creating instances easier by “encapsulating” ...