Consider a builder when faced with many constructor parameters
Static factories and constructors share a limitation: they do not scale well to large numbers of optional parameters.
Example:
public boolean isUserEnteringRow;
public boolean isUserEnteringColumn;
public boolean startOfGame;
public boolean didCurrentUserMiss;
public boolean didCurrentUserHitOwnShip;
public boolean didCurrentUserHitEnemyShip;
public boolean isShipAlreadyHit;
Traditionally, programmers have used Telescoping constructors
pattern, in which you provide a contructor
with only the required parameters, another with single optional parameters, a third with two optional parameters,
and so on, culminating in a constructor with all the optional paramters.
The telescoping constructor patterens work, but it is hard to write client code when they are many parameters, and harder still to read it.
A Second alternative when facing many contructor parameters is the JavaBeans pattern
In which you call a parametersless contructor to create the object and call the setter and getter methods to set each required parameter and each optional parameter of interest.
//JavaBeans Pattern - allows inconsistency, mandates mutability
public class NutritionFacts{
//parameters initialized to default values(if any)
private int servingSize = -1;//Required: no default values (if any)
private int servings = -1;//Required: no default values (if any)
private int calories = 0;
private int fat = 0;
private int sodium = 0;
private int carbohydrates = 0;
}
public NutritionFacts(){}
public void setServingSize(int val){
servingSize = val;
}
" "
Unfortunately, the JavaBeans pattern has serious disadvantages of its own. Because contruction is split across multiple calls, a JavaBean may be in an insconsistent state partway through its construction.
Luckily, there is a third alternative that combines the safety of telescoping constructor pattern with the readability of the JavaBeans pattern.
It is a form of the Builder
pattern.
Alternative way to construct complex objects.
Instead of making a desired object direclty, the client calls the constructor(or a static factory) with all the required
parameters and gets a builder object
. Then the client calls setter-like methods on the builder object to set each optional parameter of interest. Finally, the client calls a parameterless build
method to generate the object, which is immutable.
Builder pattern aims to “Separate the construction of a complex object from its representation so that the same construction process can create different representations.”
The builder is a static member class of the class it builds.
Example:
public class NutritionFacts{
//parameters initialized to default values(if any)
private int servingSize;
private int servings;
private int calories;
private int fat;
private int sodium;
private int carbohydrates;
public static class Builder{
//required parameters
private final int servingSize;
private final int servings;
//optional parameters
private int calories = 0;
private int fat = 0;
private int carbohydrates = 0;
private int sodium = 0;
public Builder(int servingSize, int servings){
this.servingSize = servingSize;
this.servings = servings;
}
public Builder calories(int val){
calories = val;
return this;
}
public Builder fat(int val){
fat = val;
return this;
}
public Builder sodium(int val){
sodium = val;
return this;
}
public NutritionFacts(){
return new NutritionFacts(this);
}
}
Note that NutritionFacts
is immuatable, and that all parameter default values are in a single location.
The builder’s setter methods return the builder itself so that invocations can be chained.
Here is how the client code looks:
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
calories(100).sodium(35).carbohydrates(27).build();
that above created user object does not have any setter method, so it’s state can not be changed once it has been built. This provides the desired immutability.