Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do we need a .build() method in the Builder Pattern?

I had a question regarding the "Builder Pattern" covered in "Effective Java". Do we need a .build() method for it to correctly implement the pattern? For instance, let's say that we have the following class:

public class CoffeeDrink {

    private int numEspressoShots;
    private short milkType;
    private boolean withWhip;

    private CoffeeDrink() {
    }

    public static CoffeeDrink buildNewDrink() {
        return new CoffeeDrink();
    }

    public CoffeeDrink withEspresso(int n) {
        this.numEspressoShots = n;
        return this;
    }

    public CoffeeDrink withMilkType(shot t) {
        this.milkType = t;
        return this;
    }

    public CoffeeDrink withWhip() {
        this.withWhip = true;
        return this;
    }
}

And then how we use it:

CoffeeDrink c = CoffeeDrink.buildNewDrink()
                         .withEspresso(2)
                         .withMilkType(2)
                         .withWhip();

Would this still be valid if I don't have a static inner Builder class? I guess that one of the advantages is that it holds off from creating a new CoffeeDrink object until the method .build() is called, but I'm still creating a Builder object. Just seeking some clarifications.

like image 200
victormejia Avatar asked Jan 16 '15 23:01

victormejia


2 Answers

No, this is not the Builder pattern. It's valid Java, and it will compile and run. But your buildNewDrink() method, whether it's called build() or buildNewDrink() or something else, is just a simple Factory Method that creates a CoffeeDrink. Those other methods are like setter methods that happen to return themselves.

The static nested Builder class is necessary. While holding off on creating the class instance, it can perform validation logic to ensure that an invalid object is not created. I'm not sure that there is an invalid state to a CoffeeDrink as you have it, but if it did, with your code, it would be possible to create a CoffeeDrink and have it in an invalid state after it was created, but before other methods were called. The Builder pattern eliminates this possibility by validating the data before building the instance. It also eliminates the need for constructor explosion, where lots of constructors with all possible combinations of parameters are needed, to cover all possible cases.

like image 114
rgettman Avatar answered Oct 17 '22 08:10

rgettman


According to the GoF reference, build() isn't required. The original reference doesn't use chaining, and there is a getResult() step at the end of the Director.construct() method. The Director class takes care of encapsulating the build process, so Clients don't need to worry if they're building things correctly. It's the responsibility of the Director.

Here's the sequence diagram from the GoF reference on Builder:

GoF Builder Sequence Diagram

like image 26
Fuhrmanator Avatar answered Oct 17 '22 08:10

Fuhrmanator