Effective Java : Item 2

Consider a builder when faced with many constructor parameters

The Builder Pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters.

Implement the builder pattern as opposed to providing telescoping constructor. Example : a class representing the Nutritional Facts label. These have few required fields and many optional fields.
You can get around this problem by providing telescoping constructors in which we provide a constructor with the required parameters a second with a single optional parameter a third with two optional parameters and so on. The telescoping constructor is fine, but is hard to write and harder still to read.

We can implement this a JavaBean. This does not have the disadvantages of the telescoping constructor, but the class instantiation is split across multiple set calls. The Bean is very likely to be in an inconsistent state partway though its construction. The JavaBean model precludes the possibility of making a class immutable.

The third alternative is the Builder Patten (Patterns Catalog). Instead of making the desired object directly, the client calls a constructor or a static factory method with all the required parameters and gets a builder object. The client then calls the setter like method on the builder object to set each optional parameter. Finally the client calls a parameter less build method to generate the object.

/*
 * From Effective Java Item 2.
 * Implement Builder pattern instead of telescoping constructors.
 */
public class NutritionFacts {
 
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrates;
 
    public static class Builder {
        /*
         * required paramters.
         */
        private final int servingSize;
        private final int servings;
 
        /*
         * Optional params initialized to default values.
         */
        private int calories      = 0;
        private int fat           = 0;
        private int sodium        = 0;
        private int carbohydrates = 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 Builder carbohydrates (int val) {
            carbohydrates = val;
            return this;
        }
 
        /*
         * A parameter less build method that assembles and returns the object.
         */
        public NutritionFacts build () {
            return new NutritionFacts(this);
        }
    }
 
    /*
     * private method of Class that leeches off the Builder class.
     */
    private NutritionFacts (Builder builder) {
        servingSize   = builder.servingSize;
        servings      = builder.servings;
        calories      = builder.calories;
        fat           = builder.fat;
        sodium        = builder.sodium;
        carbohydrates = builder.carbohydrates;
    }
}

Notes

The NutritionFacts class is immutable. The builders setters method returns the builder itself so that the invocation can be chained.

NutritionFacts cocaCola = new NutritionFacts.builder(240, 19).calories(10).sodium(100).carbohydrates(10).build();

Advantages

  • Builder Pattern simulates named optional parameters.
  • Builders can have multiple vararg parameters.
  • A single builder can be used to build multiple objects.
  • A builder can fill in fields automatically such as a serial number or a date time stamp.

Disadvantages

  • More verbose than telescoping constructor
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License