3

Recently I saw some of the developers coding their VOs with nested builder class like

public class User {

    private String firstName;
    private String lastName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public static class UserBuilder {

        private String firstName;
        private String lastName;

        public User build() {
            User user = new User();
            user.firstName = firstName;
            user.lastName = lastName;
            return user;
        }

        public UserBuilder withFirstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public UserBuilder withLastName(String lastName) {
            this.firstName = firstName;
            return this;
        }       
    }

}

Now, they claim that this makes code more readable. My point is, this has following disadvantages:

  1. I can't simply add fields and expect my IDE to complete code for me, as now I need to update this inner class too.

  2. Simple POJOs are carrying code which is not relevant for VO.

I am looking for any advice if I am missing something here. Feel free to add your thoughts about the same.

Sample code after this modification looks like,

User user = new User.UserBuilder()
                .withFirstName("Name")
                .withLastName("surName")
                .build();
shmosel
  • 49,289
  • 6
  • 73
  • 138
Prateek Jain
  • 2,738
  • 4
  • 28
  • 42
  • 1
    You usually use builders when you have many different possibilities for your constructor and many of them are of the same type. Thus, a builder makes everything more readable and reusable. – LordAnomander Feb 09 '16 at 09:09
  • 9
    Builders avoid the "telescoping constructor" antipattern, wherein you end up with a combinatorial explosion of all of the possible optional constructor parameters. There is a detailed discussion in Effective Java 2nd Ed Item 2. – Andy Turner Feb 09 '16 at 09:11
  • reduces the amount of code as you can create objects with possible combinations rather than using different constructors – Bilbo Baggins Feb 09 '16 at 09:11
  • 2
    http://stackoverflow.com/questions/328496/when-would-you-use-the-builder-pattern This link provides all the information you should know about the usage of the builder pattern. – LordAnomander Feb 09 '16 at 09:17
  • 6
    I think builders are most useful for constructing immutable objects, where you would otherwise have to pass all the arguments into a constructor. The builder pattern makes construction more readable and flexible. But in your example `User` is mutable, so there's no much you can do with the builder that you can't do with the setters. – shmosel Feb 09 '16 at 09:19
  • On a different note I would also advice to have a look at lombok to use the pattern and avoid the boilerplate code. That will also help to simply add a filed and ide will show it up. Disclaimer - I use lombok extensively but do not represent them in any way. – Amod Pandey Feb 09 '16 at 09:21
  • For example which you provided, there is no need for using builder pattern, but imagine situation when you have single constructor with N arguments, and when you want to create instance of class, you want to set some arguments leaving rest of them as default. this is situation where you use builder pattern – user902383 Feb 09 '16 at 09:21
  • Thanks guys, I know what is the intent of builder pattern but what I am interested here is to know; if it is reasonable to build POJOs in this fashion? For me, it doesn't add any value as such. – Prateek Jain Feb 09 '16 at 09:23
  • 1
    Josh bloch explains the use case - http://www.informit.com/articles/article.aspx?p=1216151&seqNum=2 – XOXO Feb 09 '16 at 09:27
  • 1
    This should make you clear, why, what and how with a simple example. https://dzone.com/articles/factories-builders-and-fluent- – Lokesh Feb 09 '16 at 12:15
  • Using java 8 you can get rid of some boiler plate builder code. You would just need the immutable object and a mutable POJO for it. I wrote an anser about it here: http://stackoverflow.com/questions/31754786/how-to-implement-the-builder-pattern-in-java-8/31754787#31754787 – SpaceTrucker Feb 10 '16 at 09:33

3 Answers3

1

Here is an article from Joshua Bloch. He explains very well why, when and how to use a builder : http://www.informit.com/articles/article.aspx?p=1216151&seqNum=2

It is one of items in his book called Effective Java. I strongly advise you to read this book if you have a little experience with Java.

Main point :

When you you get a class with a lot of attribute there is several ways create an object and init it.

If you set one by one every attributes it can be wordy and your object could be altered after its creation. With this method it is impossible to make your class immutable and you cannot be sure that your object is in consistent state.

Exemple from the article :

public class NutritionFacts {
    // Parameters initialized to default values (if any)
    private int servingSize  = -1; // Required; no default value
    private int servings     = -1;  //     "     "      "      "
    private int calories     = 0;
    private int fat          = 0;
    private int sodium       = 0;
    private int carbohydrate = 0;

    public NutritionFacts() { }
    // Setters
    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; }
}

You can use a telescoping constructor. It can make your object immutable. However if you get many attributes it can be hard to write and read your code. More over when you just want create with one setted attribute, and unfortunately this one is the last parameter of the constructor, you have to set all parameter anyway.

Exemple from the article :

public class NutritionFacts {
    private final int servingSize;  // (mL)            required
    private final int servings;     // (per container) required
    private final int calories;     //                 optional
    private final int fat;          // (g)             optional
    private final int sodium;       // (mg)            optional
    private final int carbohydrate; // (g)             optional

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

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

    public NutritionFacts(int servingSize, int servings,
            int calories, int fat) {
        this(servingSize, servings, calories, fat, 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, int carbohydrate) {
        this.servingSize  = servingSize;
        this.servings     = servings;
        this.calories     = calories;
        this.fat          = fat;
        this.sodium       = sodium;
        this.carbohydrate = carbohydrate;
    }
}

The builder allows to make your code more readable and easy to write. It also allows you to be able to make your class immutable.

Exemple from the article :

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 {
        // Required parameters
        private final int servingSize;
        private final int servings;

        // Optional parameters - initialized to default values
        private int calories      = 0;
        private int fat           = 0;
        private int carbohydrate  = 0;
        private int sodium        = 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 carbohydrate(int val)
            { carbohydrate = val;  return this; }
        public Builder sodium(int val)
            { sodium = 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;
    }
}

In your example I'm not sure that it is very useful to do a builder for a class with only two attributes.

I hope this will help you.

Thomas Betous
  • 4,633
  • 2
  • 24
  • 45
0

IMHO in the given example you gain no value by using Builder pattern. You can create User object without the Builder (because of all the setters). The only thing that Builder gives you in this particular case is Fluent Interface.

You should use Builder Pattern when there are various combinations of creating a valid object. Thanks to this you won't have to implement many constructors or factory methods.

Builder is also helpful when creating a valid object requires many parameters.

Builder should be responsible for build only a valid objects. In your case, if User needs to have first and last name Builder shouldn't allow to create the instance of User that doesn't have those attributes set.

0

Start with small immutable objects

If all your properties are required then you should use just constructor. By doing this you might create nice small immutable object.

Builders are helpful when you have multiple optional fields

If there are multiple optional fields and different ways to create an object you'd need multiple constructors.

public User (int requiredParameter) { ... }
public User (int reqiredParameter, int optionalParameter) { ... }
public User (int reqiredParameter, int optionalParameter, String optionalParameter2) { ... }
public User (int reqiredParameter, String optionalParameter2) { ... }

It creates messy code. It is hard to determine which constructor you should use. In this case you could use nested builder to have intuitive way of creating your object.

Marcin Szymczak
  • 11,199
  • 5
  • 55
  • 63