Sunday, December 18, 2011

Creating Java Object -- Part-II

Continued from previous post…

The second of way of creating object is as follows:

Builder pattern
This is really an interesting pattern which I have come across lately. Consider a class where there are many fields in which some are quint essential to be initialized and some may not at the time of creating object. In that case we would end up giving n number of constructors in which we may not be knowing which to use and which not to. For e.g 

 public class NutritionFacts {
        private final int servingSize; // required
        private final int servings; // required
        private final int calories; // optional
        private final int fat; // optional
        private final int sodium; // optional
        private final int carbohydrate;

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

        public NutritionFacts(int servingSize, int servings, int calories, int fat, int sodium, int carbohydrate) {
            super();
            this.servingSize = servingSize;
            this.servings = servings;
            this.calories = calories;
            this.fat = fat;
            this.sodium = sodium;
            this.carbohydrate = carbohydrate;
        }
}
 This is called telescoping constructor pattern.  Though this pattern may help in some of the scenarios but it goes out of hand when the parameters go on increasing. Consider creating an object to the above class, you may not be knowing which constructor to call for which case.
An alternate we may think of is JavaBeans pattern. By that we can have only only setters and getters for the parameters and initialize it wherever we need. But by this way we may not be able to handle the creation. As in, a JavaBean may be in an inconsistent state partway through its construction.  One more disadvantage associated to this is that the JavaBeans pattern precludes the possibility of making a class immutable, which in turn would require more effort from the developer to keep it thread safe.

After coming through all this the third alternative that we have is builder pattern.  In this instead of making an object directly, we can call a builder object.  Then the client can set optional parameters if required by calling setters on the builder object. For e.g


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 carbohydrate;

    public static class Builder {
        private int servingSize;
        private int servings;

        private int calories = 0;
        private int fat = 0;
        private int sodium = 0;
        private int carbohydrate = 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 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;
    }

}
            Now the object can be created as,
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).calories(100).sodium(45).build();
        System.out.println("cocaCola:" + cocaCola.calories);

In order to have builder instead of going and creating it inside the class we can also have Builder interface and just implement it.
Though it has disadvantage of writing builders for each class, but when you see from the perspective of handling this kind of situation then it is worth it I think.  At least better than the telescoping and JavaBeans patterns.

{Courtesy: Effective Java - Joshua Bloch} 

No comments:

Post a Comment