Question

Which of the following is the better approach to implement the builder pattern?

1) Using the object to build instead of all its properties in the builder (and create it in the builder constructor):

public class Person {
    private String firstName;
    // other properties ...

    private Person() {}

    // getters ...

    public static class Builder {
        // person object instead of all the person properties
        private Person person;

        public Builder() {
            person = new Person();
        }

        public Builder setFirstName(String firstName) {
            person.firstName = firstName;

            return this;
        }

        // other setters ...

        public Person build() {
            if (null == person.firstName) {
                throw new IllegalStateException("Invalid data.");
            }

            return person;
        }
    }
}

2) Using the properties of the object to build instead of the object directly in the builder (and create it in the build() method):

public class Person {
    private String firstName;
    // other properties ...

    private Person() {}

    // getters ...

    public static class Builder {
        // person properties instead of object
        private String firstName;
        // other properties ...

        public Builder() {}

        public Builder setFirstName(String firstName) {
            this.firstName = firstName;

            return this;
        }

        // other setters ...

        public Person build() {
            if (null == this.firstName) {
                throw new IllegalStateException("Invalid data.");
            }

            Person person = new Person();
            person.firstName = firstName;

            return person;
        }
    }
}

I prefer the first way because i think that with lots of properties repeat them in the builder is redundant. Are there some disadvantages with the first approach?

Thanks in advance and sorry for my bad english.

Was it helpful?

Solution

Small Note : Yes the properties might be a repeat but they have advantages

Details below : If you look at the details here.

Pizza pizza = new Pizza(12);
pizza.setCheese(true);
pizza.setPepperoni(true);
pizza.setBacon(true);

The problem here is that because the object is created over several calls it may be in an inconsistent state partway through its construction. This also requires a lot of extra effort to ensure thread safety.

The better alternative is to use the Builder Pattern.

Notice below method in Builder and respective constructor or parent Pizza class - full code in link here

 public static class Builder {

    public Pizza build() {    // Notice this method
      return new Pizza(this);
    }
  }

  private Pizza(Builder builder) {  // Notice this Constructor
    size = builder.size;
    cheese = builder.cheese;
    pepperoni = builder.pepperoni;
    bacon = builder.bacon;
  }

OTHER TIPS

The Builder pattern has been described in the Gang of Four “Design Patterns” book that says:

The builder pattern is a design pattern that allows for the step-by-step creation of complex objects using the correct sequence of actions. The construction is controlled by a director object that only needs to know the type of object it is to create.

If there is a sequence of steps that needs to be followed while constructing the object then go for second option.

In your first option correct sequence of actions are not controlled. You can go for either option if sequence of actions are not defined.

I think in your case there is no matter where to create the object. The builder would be used the same way in both cases with minimum difference in performance.

But if the object is immutable and it's field could be created with more than one step then I would certainly go with the second approach. For example you can check the source code of java.lang.StringBuilder and see that the String object is created in the last step:

public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);
}

Moreover I prefer the Wizard pattern. It is an extension of the Builder pattern which protects you from getting IllegalStateException.

public class Person {

    private String firstName;
    // other properties ...

    private Person() {}

    // getters ...

    public static class Builder {

        public Builder() {}

        public FirstStep setFirstName(String firstName) {
            return new FirstStep(firstName);
        }

        public static class FirstStep {

            private String firstName;

            private FirstStep(String firstName) {
                this.firstName = firstName;
            }

            public Person build() {
                Person person = new Person();
                person.firstName = firstName;
                return person;
            }
        }
    }
}

You can use lombok builder annotation

Example :

@Data
@Builder
public class Person{
  private String name;
  private String city;
  private String job;
}

Usage :

Person.builder()
.name("Adam Savage")
.city("San Francisco")
.job("Mythbusters")
.build();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top