duke

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);
        } 
    }
}