Do we need a .build() method in the Builder Pattern?
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 Client
s 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:
Related videos on Youtube
victormejia
Updated on July 04, 2022Comments
-
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 newCoffeeDrink
object until the method.build()
is called, but I'm still creating aBuilder
object. Just seeking some clarifications.-
scottb almost 8 yearsThe 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 over 9 yearsI 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 over 9 yearsThanks for the clarifications. So would I validate all parameters in the builder function of the Builder class, before returning the instance of CoffeeDrink?
-
rgettman over 9 yearsYes. 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 over 9 yearsThe Builder pattern by the GoF (Gamma et al) has no
build()
method. It does say ConcreteBuilders providean 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.