[Read Effective Java] Chapter 2 Item 2 "Consider a builder when faced with a large number of constructor parameters"

Consider the builder when faced with numerous constructor parameters

When creating a class that requires a lot of parameters to be passed when newing Talking about using "builder" for readability and safety

Sample code

Nutrition Facts is a class that represents nutritional components Amount for one person, amount per container, calories for one person, etc. Let's consider three patterns as an example when you have many fields. ・ Telescoping constructor pattern The disadvantage is that if there are many parameters, it will be difficult to understand what to pass as an argument when newing, and readability will also decrease.

· JavaBeans pattern Readability is improved unlike the telescoping constructor pattern, but inconsistent states occur while setting parameters.

・ Builder pattern The best of telescoping constructors and JavaBeans!

Example 1


//Telescoping constructor pattern
public class NutritionFacts{
    private final int servingSize;  //(mL)Mandatory
    private final int servings;     //(Per container)Mandatory
    private final int calories;     //option
    private final int fat;          //(g)option
    private final int sodium;       //(mg)option
    private final int carbohydrate; //(g)option

    public NutritionFacts(int servingSize, int servings){
        this(servingSize, servings, 0, 0, 0, 0);
    }

    public NutritionFacts(int servingSize, int servings, 
             int calories ){
        this(servingSize, servings, calories, 0, 0, 0);
    }
    
    public NutritionFacts(int servingSize, int servings,
            int calories, int fat ){
        this(servingSize, servings, calories, fat, 0, 0);
    }

    public NutritionFacts(int servingSize, int servings,
            int calories, int fat, int sodium ){
        this(servingSize, servings, calories, fat, sodium, 0);
    }

    public NutritionFacts(int servingSize, int servings,
            int calories, int fat, int sodium, carbohydrate ){
        this.servingSize   = servingSize;
        this.servings      = servings;
        this.calories      = calories;
        this.fat           = fat;
        this.sodium        = sodium;
        this.carbohydrate  = carbohydrate;
    }
}

//It's hard to see when new
NutritionFacts cocaCola = new NutritionFacts(240, 8, 100, 0, 35, 27);

Example 2


//JavaBeans pattern
public class NutritionFacts{
    private int servingSize  = -1; //(mL)Mandatory
    private int servings     = -1; //(Per container)Mandatory
    private int calories     = 0;  //           
    private int fat          = 0;  //(g)        
    private int sodium       = 0;  //(mg)       
    private int carbohydrate = 0;  //(g)        

    public NutritionFacts(){ }

    //Setter
    public void setServingSize(int val)  { servingSize = val;}
    public void setServings(int val)     { servings = val;}
    public void setCalories(int val)     { calories = val;}
    public void setFat(int val)          { fat = val;}
    public void setSodium(int val)       { sodium = val;}
    public void setCarbohydrate(int val) { carbohydrate = val;}
}

//It's easy to see when new, but it's a little troublesome if it is accessed while setting
NutritionFact cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);

Example 3


//Builder pattern
public class NutritionFacts{
    private final int servingSize;  //(mL)       
    private final int servings;     //(Per container)
    private final int calories;     //           
    private final int fat;          //(g)        
    private final int sodium;       //(mg)       
    private final int carbohydrate; //(g)        

    public static class Builder{
        //Required parameters
        private final int servingSize;  //(mL)       
        private final int servings;     //(Per container)
        
        //Optional parameters
        private int calories     = 0;  //           
        private int fat          = 0;  //(g)        
        private int sodium       = 0;  //(mg)       
        private int carbohydrate = 0;  //(g)   

        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 carbohydrate(int val){
            carbohydrate = val;
            return this;
       }

       public NutritionFacts build() {
           return new NutritionFacts(this);
       }
    }

    private NutritionFacts(Builder builder){
         servingSize  = builder.servingSize;
         servings     = builder.servings;
         calories     = builder.calories;
         fat          = builder.fat;
         sodium       = builder.sodium;
         carbohydrate = builder.carbohydrate;
    }
}

//Easy to see and safe when new!
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
    calories(100).sodium(35).carbohydrate(27).build();

Recommended Posts

[Read Effective Java] Chapter 2 Item 2 "Consider a builder when faced with a large number of constructor parameters"
[Read Effective Java] Chapter 2 Item 4 "Force uninstantiation with a private constructor"
[Read Effective Java] Chapter 2 Item 1 "Consider static factory methods instead of constructors"
[Read Effective Java] Chapter 3 Item 12 "Considering Implementation of Comparable"
[Read Effective Java] Chapter 2 Item 3 "Force singleton characteristics with private constructor or enum type"
[Read Effective Java] Chapter 3 Item 9 "When overriding equals, always override hashCode"
[Read Effective Java] Chapter 2 Item 5 "Avoid the creation of unnecessary objects"
[Read Effective Java] Chapter 2 Item 7 "Avoid Finalizers"
[Read Effective Java] Chapter 3 Item 8 "When overriding equals, follow the general contract"
[Read Effective Java] Chapter 3 Item 10 "Always Override toString"
[Read Effective Java] Chapter 2 Item 6 "Remove obsolete object references"
[Java] JUnit that NG if a method with a large number of lines is detected using black magic
Force non-instantiation with Effective Java private constructor