The classic Builder design pattern is one of the creational design patterns used in object-oriented programming, as defined by the Gang of Four, and helps to separate the creation of complex objects from their implementation. This can be very useful when you want to create representations of the same object, with three, four or even more attributes, over and over again.
As part of this pattern there’s a Director class, which orchestrates the creation of something. The Builder is usually an abstract interface that specifies how to build that something in small incremental steps. A Concrete Builder will implement the builder interface to create different representations of your object and track them as they change. The concrete builder also has the ability to retrieve the final Product, which is the representation of the complex object that you want to build in the first place.
Although this design pattern reduces complexity and encapsulates the creation and assembly of different parts of a complex object, sometimes our code might become harder to read. Every so often you might want to make it more business readable and highlight the domain concepts. This is where a fluent interface comes into play. Not to be confused with method chaining (although method chaining is a way to implement a fluent interface).
If we take a look at the creation of a Pizza object (apologies if this will make you hungry), it could look like this:
The constructor for Pizza forces you to pass all those attributes every time you want to create a new representation. If you want flexibility you might end up creating different constructors in your class. One that might not accept a sauce, one that might take an extra attribute when your pizza is special like a calzone, and the list goes on.
What if we could instead do…
This interface emphasises the different parts that can be added to your Product while making it super easy to read in a business context. Each of the methods being chained return your Builder and at the end you get your Product, with
.Bake() in this case.
If we have a look at the code inside the Builder, we can see simple methods that set the properties on the object being created. You can spot your half-baked product (see what I did there?) inside the class, ready to be returned by your
.Build() method, the
.Bake() in our example.
To take it to the next level, from an implementation perspective, would be to create some interfaces that would force the user to follow a specific path to create an object, in case there are some prerequisites that need to be met to build a specific part of your Product. You wouldn’t want to add toppings to your pizza before adding the sauce. Your
.WithSauce() might return an interface
IPizzaBuilderToppings. The method would look like this:
The interface would define the method
.AddTopping(), that in turn would force you to either add more toppings or just
.Bake() it. Your PizzaBuilder would then inherit from all these interfaces.
Give the Fluent Builder a try the next time you are writing some unit tests, and you will see that building the complex database client will become much easier, verbose and clearer to understand and read.
Disclaimer: No pineapple was added in the making of this post.
Source code can be found in GitHub
My name is André Guedes and I’m a Software Engineer at ASOS. I joined just over a year ago and really enjoy the combination of tech and fashion! I’m from sunny Portugal, so I love good food, either out or cooking at home. I’m a series addict, so I’m often found watching a good drama/thriller, while nibbling something of course :)