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

11,882

Solution 1

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.

Solution 2

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

Share:
11,882

Related videos on Youtube

victormejia
Author by

victormejia

Updated on July 04, 2022

Comments

  • victormejia
    victormejia almost 2 years

    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.

    • scottb
      scottb almost 8 years
      The Builder Pattern is used to great advantage with immutable classes. With them, the Builder is a mutable "helper" class that assists in the ultimate construction of the final product which is thereafter immutable. Your example is merely a simple POJO and it shares the disadvantages of JavaBeans (mutable, can be viewed in an incomplete or inconsistent state, etc.).
  • afsantos
    afsantos over 9 years
    I agree with your remarks. These methods seem to be regular setters with chaining. Just a minor detail, but you might be missing a "not" in your answer, as in "it can perform validation logic to ensure that an invalid object is not created".
  • victormejia
    victormejia over 9 years
    Thanks for the clarifications. So would I validate all parameters in the builder function of the Builder class, before returning the instance of CoffeeDrink?
  • rgettman
    rgettman over 9 years
    Yes. The build() method is called last in the chain. It validates all data previously passed in, and it creates and returns the desired instance.
  • Fuhrmanator
    Fuhrmanator over 9 years
    The Builder pattern by the GoF (Gamma et al) has no build() method. It does say ConcreteBuilders provide an interface for retrieving the product, e.g., GetMaze() to return the maze that was build in steps. None of the sample code in GoF uses chaining. Many people use Builder differently than GoF. Their idea was to have directors that encapsulate all the build steps. The idea of "validating" is less important since the concrete builder is not code on the client but code controlled by the API provider inside the director.