Home > OS >  Why to use #newBuilder() function in Builder Pattern? Is it mandatory?
Why to use #newBuilder() function in Builder Pattern? Is it mandatory?

Time:07-06

I am using the Builder Pattern since time ago, but these days one of my collegues reach me with a question to which I never thought about, and is about the #newBuilder() function in the Builder Pattern.

I've seen in several forums, tutorials, and even APIs, that when using the Builder Pattern, a structure like this is usually used:

Car car1 = new CarBuilder().newBuilder().twoDoors().fourWheels().build();

Usually, inside of the #newBuilder() function, there is a code like this:

public static CarBuilder newBuilder(){
  return new CarBuilder();
}

The question is, why should be needed a #newBuilder() function in the Builder class? Is it a good practice to have it, or is needed only when overloading is applied? I mean, just in the cases where I need to overload the #newBuilder() having 2 or 3 different #newBuilder() functions with different parameters.

What if I will have only one #newBuilder() function in the Builder class? Should I implement it, or can I avoid it and do something like:

Car car1 = new CarBuilder().twoDoors().fourWheels().build();

The question of my colleague was: If I implement the #newBuilder() function, am I falling in redundancy with the first example if I will only have one #newBuilder() function in my Builder class?

What you think about this? Should I remove it or it is justified to have the #newBuilder() function despite of I have only one implementation of it without overloading?

Thanks!

CodePudding user response:

Note that this:

Car car1 = new CarBuilder().newBuilder().twoDoors().fourWheels().build();

Is definitely redundant, but not because the newBuilder() method exists. The problem is your code is essentially this:

CarBuilder builder1 = new CarBuilder();
CarBuilder builder2 = builder1.newBuilder();
Car car1 = builder2.twoDoors().fourWheels().build();

In other words, you're creating two instances of CarBuilder. Also, you're calling a static method on an instance reference, which is frowned upon. With your current setup, your code should be either:

Car car1 = new CarBuilder().twoDoors().fourWheels().build();

OR:

Car car1 = CarBuilder.newBuilder().twoDoors().fourWheels().build();

Which style you choose is up to you. However, if you choose to use the second approach (the static factory method newBuilder()), then typically the builder's constructor is made private, or at least package-private, so that new CarBuilder() cannot be used by external code.

So, I would say "no", having newBuilder() is not redundant in and of itself, as long as you use it correctly. It's simply an alternative way of creating a builder instance without calling the constructor directly. Note using the static factory method approach may aid in readability, because you can name the method something more descriptive. You may not see that advantage unless you have a significant number of different factory methods with different semantics, however.


Another thing to consider is where to place the newBuilder() static method. If CarBuilder and Car are extremely coupled, then many developers will put the static method in the Car class instead of the CarBuilder class (if not just nest the latter in the former).

For example:

package sample;

public final class Car {

  public static CarBuilder newBuilder() {
    return new CarBuilder();
  }

  private final int numberOfDoors;
  private final int numberOfWheels;

  Car(CarBuilder builder) {
    this.numberOfDoors = builder.numberOfDoors;
    this.numberOfWheels = builder.numberOfWheels;
  }

  // getters and setters omitted for brevity
}
package sample;

public final class CarBuilder {

  private int numberOfDoors; // should initialize to sensible default
  private int numberOfWheels; // should initialize to sensible default

  CarBuilder() {}

  public CarBuilder twoDoors() {
    numberOfDoors = 2;
    return this;
  }

  public CarBuilder fourWheels() {
    numberOfWheels = 4;
    return this;
  }

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

Which could then be used like so:

Car car1 = Car.newBuilder().twoDoors().fourWheels().build();
  • Related