Firstly my main complaint isn't against the constructor in general... which is good because they obviously can't be entirely avoided in code... but against constructors with arguments specifically. I will argue that they tend to obfuscate code and limit the extendability of classes. I'll illustrate with an example.
Say I have a class called Circle which represents a circle on a plane (e.g. to be drawn on a display). Maybe I want to make this class sophisticated such that a programmer can be flexible in its construction. I might provide, for instance, a constructor that takes a center point and a radius and another that takes three points. Since a circle on a plane can be uniquely identified by its center and radius, or by three points on that plane, this sounds reasonable. So our constructor signatures might look like this:
public Circle(Point center, double radius)
public Circle(Point p1, Point p2, Point p3)
Looks good, at first... but wait! What are those three points? Are they three points on the circumference or a center point and two points on the circumference? Either case can uniquely construct a circle on a plane. How without (shudder the thought) reading the Javadoc is the poor programmer to know what the constructor is going to do? The reader might suggest that we could change the second constructor's arguments a bit to resolve this complication, say:
public Circle
(Point center, Point onCircumference1, Point onCircumference2)
This does resolve the ambiguity but also requires the programmer to have access to the constructor's signature. Using a modern IDE, say Eclipse, this is likely rarely a difficulty. They all have nice mechanisms for examining such details. But what if you're trying to read some code somewhere where your fancy IDE isn't available? Say on a Unix console in vi (some of us still need to do that from time to time, right?) or on somebodies poorly written blog? What if there's a line of code like:
Circle myCircle =
new Circle(new Point(10,10), new Point(25,25), new Point(50,50));
What kind of circle does that make? It's impossible to know without drilling down into the API, which seems like such a waste of time. Many (hopefully one day all) programmers have become accustomed to the concept that well chosen method names serve as implicit documentation and make code more readable. If method names are descriptive and methods are kept small then code readability skyrockets. Why are we making an exception in the critical area of object construction? Fortunately, there is an alternative. What if we ditch the constructor and add a new static method to the Circle class:
public static Circle makeCircleFromThreeCircumferencePoints
(Point p1, Point p2, Point p3) {
Circle newCircle = new Circle();
//Insert fancy math algorithm here
return newCircle;
}
Now what the method does is unambiguous: it makes a new Circle instance given three points on the circumference. Any programmer who can read English will see that quickly without any added documentation. What's more, with a good IDE simply typing Circle then a "." will bring up a list of static methods including this one from which you can choose. The programmer will quickly find what he's looking for without skipping a beat in his train of thought. How that would be accomplished with a constructor, and without a photographic memory, is hard to imagine. Some readers will, rightfully, object to the parameters having names like p1, p2, p3, preferring something like circumferencePoint1, etc. They're probably right, but since my method name is so descriptive that's somewhat redundant.
In case the reader remains unconvinced, being of the belief that self documenting code is overrated, there are more issues with constructors. They don't only make code hard to read, they limit what it can do. Specifically they make it inflexible. To illustrate, suppose in addition to creating circles given the center and radius we wish to be able to construct them given the center and circumference. How can we provide this functionality using constructors? If we need a constructor taking a point and a double for this purpose, and that is already taken to construct circles based on a center and a radius, what do we do? Create a new constructor with the arguments reversed? No doubt such abominations exist, but if one decides programmers are too lazy to divide by two and will want to also construct circles given a center and diameter? One is truly stuck.
So, to conclude, lets make our truly readable and flexible Circle class:
public class Circle{
private Circle() {
//We don't want anybody constructing un-configured Circles.
}
public static Circle makeCircleFromThreeCircumferencePoints
(Point p1, Point p2, Point p3) {
Circle newCircle = new Circle()
//Insert fancy math algorithm here
return newCircle;
}
public static Circle makeCircleFromCenterPointAndRadius
(Point center, double radius) {
Circle newCircle = new Circle()
//Insert fancy math algorithm here
return newCircle;
}
public static Circle makeCircleFromCenterPointAndCircumference
(Point center, double circumference) {
Circle newCircle = new Circle()
//Insert fancy math algorithm here
return newCircle;
}
}
So that's it... easy to read, easy to use and easy to extend. If I need new ways to build circles I add new static factories, not needing to worry that I've made the API hard to understand or needing to concoct fancy ways around already used argument type lists. Note the private constructor. This makes it so that the only way to create new Circle instances is via the static factories. The only place a Circle constructor is used is in the factory methods themselves (there's to way around that). What if we actually wanted to give the ability to generate unconfigured Circles, for configuration later? Rather than making the noarg constructor public I would still recommend creating a no argument factory, say makeUnconfiguredCircle. That way the point is explicit and the API consistent.
Finally, should one ever let classes have public constructors? While I will agree that there are cases where it is harmless to leave classes with, say, single noarg constructors I would personally discourage it. Firstly, if one is going to use static factories for classes that need to be initialized configured then using static factories in all cases will keep the API consistent. Secondly, maybe a class starts out simple, needing only a single constructor for example, but can one guarantee that it will stay that way? Our circle may have started out only needing center and radius construction, but needs expanded as the project evolved, as always. Now one either needs to refactor all the code already building Circles or mix and match constructors with static factories... not a disaster, perhaps, but at least a little ugly.
So hopefully I've convinced somebody and there will be a few less constructors littering the APIs of the future.