Ladder of constructors - pattern or anti-pattern?
The ladder of constructors is a popular pattern one can see in Java applications. In this post, let us try to understand where this pattern becomes necessary and what features the programming languages can provide to come out of the ladder of constructors.
Context
We want to create a class whose fields we want to initialise using constructors (we want the users of the class to pass these values into the class). Let us prefer constructors here and not setters/ other regular methods. If we opt for constructors, then when the object is ready for use, it would have the necessary values initialised - which is prone to fewer errors.
Java solution:
Let's attempt to solve this problem with Java. Let us start with the following code.
package com.nareshak.demo;
public class Person {
private String firstName;
private String lastName;
private int age;
// Getters
}
Let us assume that "first name" is mandatory and the other two fields are optional.
If we create one constructor with three arguments, it would lead to a few issues. The user must specify the values of lastName
and age
. There is no way for him to understand what default values to be assumed for them. Hence, it is better that he is taken away from the responsibility of specifying values for lastName
and age
.
Since Java allows overloading constructors, we can take that approach. The code would look as follows.
package com.nareshak.demo;
public class Person {
private String firstName;
private String lastName;
private int age;
public Person(String firstName) {
this(firstName, null);
}
public Person(String firstName, String lastName) {
this(firstName, lastName, 18);
}
public Person(String firstName, String lastName, int age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
// Getters
}
The actual initialisation of instance fields happens in the three-argument constructor. This way, we have encapsulated the logic to assign default values to fields inside the class and avoided duplicate code. Suppose the user invokes a constructor passing firstName
as null. This can be handled in the last constructor. If we initialise the fields in every constructor, then we would have ended up with duplicate code for initialisation and error handling.
Hence, we can say that the ladder of constructors is a pattern in Java.
Groovy solution
Now, let us see how Groovy simplifies this.
package com.nareshak.demo
class Person {
String firstName
String lastName
int age
Person(String firstName, String lastName=null, int age=18) {
this.firstName = firstName
this.lastName = lastName
this.age = age
}
}
The feature that helped us eliminate the ladder of constructors is - default values for the parameters. By specifying a default value for a parameter, Groovy makes the corresponding argument optional.
Conclusion
In any language that supports default parameter values and, henceforth, optional arguments for the methods, we wouldn't require the ladder of constructors. With this understanding, we can say it is an anti-pattern in Groovy.
Note that many programming languages support default arguments, including Ruby, Python, Kotlin, etc.
If you are thinking about JavaScript, it has a different approach to function arguments. More of that in this post!