Telescoping constructor -vs- Builder pattern
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. Consider the case of a class representing the options on a car build. Thera are more than twenty options spotlights, parkingSensors, heatedSeats, dualZoneAC, reversingCamera, autoParking and so on. Most options are false for optionals.
What sort of constructors or static factories should you write for such a class? Traditionally, programmers have used the telescoping constructor pattern, in which you provide a constructor with only the required parameters, another with a single optional parameter, a third with two optional parameters, and so on, culminating in a constructor with all the optional parameters. Here’s how it looks in practice. For brevity’s sake, only four optional options are implemented
Telescoping constructor pattern - does not scale well!
public class Options {
private final Boolean spotlights; // required
private final Boolean parkingSensors; // required
private final Boolean heatedSeats; // optional
private final Boolean dualZoneAC; // optional
private final Boolean reversingCamera; // optional
private final Boolean autoParking; // optional
public Options(int spotlights, int parkingSensors) {
this(parkingSensorsize, parkingSensors, false);
}
public Options(int spotlights, int parkingSensors,
int heatedSeats) {
this(spotlights, parkingSensors, heatedSeats, false);
}
public Options(int spotlights, int parkingSensors,
int heatedSeats, int dualZoneAC) {
this(spotlights, parkingSensors, heatedSeats, dualZoneAC, false);
}
public Options(int spotlights, int parkingSensors,
int heatedSeats, int dualZoneAC, int reversingCamera) {
this(spotlights, parkingSensors, heatedSeats, dualZoneAC, reversingCamera, false);
}
public Options(int spotlights, int parkingSensors,
int heatedSeats, int dualZoneAC, int reversingCamera, int autoParking) {
this.spotlights = spotlights;
this.parkingSensors = parkingSensors;
this.heatedSeats = heatedSeats;
this.dualZoneAC = dualZoneAC;
this.reversingCamera = reversingCamera;
this.autoParking = autoParking;
}
}
Hand coded builder
public class Options {
private final Boolean spotlights; // required
private final Boolean parkingSensors; // required
private final Boolean heatedSeats; // optional
private final Boolean dualZoneAC; // optional
private final Boolean reversingCamera; // optional
private final Boolean autoParking; // optional
Options(int spotlights, int parkingSensors,
int heatedSeats, int dualZoneAC, int reversingCamera, int autoParking) {
this.spotlights = spotlights;
this.parkingSensors = parkingSensors;
this.heatedSeats = heatedSeats;
this.dualZoneAC = dualZoneAC;
this.reversingCamera = reversingCamera;
this.autoParking = autoParking;
}
public Builder builder() {
return new Builder();
}
public class Builder {
private Boolean spotlights;
private Boolean parkingSensors;
private Boolean heatedSeats = false;
private Boolean dualZoneAC = false;
private Boolean reversingCamera = false;
private Boolean autoParking = false;
public Builder spotlights(boolean b) { spotlights = b; return this; }
public Builder parkingSensors(boolean b) { parkingSensors = b; return this; }
public Builder setHeatedSeats(boolean b) { heatedSeats = b; return this; }
public Builder dualZoneAC(boolean b) { dualZoneAC = b; return this; }
public Builder dualZoneAC(boolean b) { dualZoneAC = b; return this; }
public Builder autoParking(boolean b) { autoParking = b; return this; }
public Options build() {
return new Options(
spotlights,
parkingSensors,
heatedSeats,
dualZoneAC,
reversingCamera,
autoParking);
}
}
}