Builder Pattern with Java examples

What is Builder Pattern?

Builder pattern is a creational design pattern. The main intention of the builder pattern is to create complex objects by separating the construction process from its representation. This pattern enables the polymorphism by providing an effective solution for creating different forms of an object while using a consistent construction process.

The GOF definition for builder pattern is,

‘Separate the construction of a complex object from its representation so that the same construction process can create different representations’

In simple words, the process of constructing a complex object should be generic. That is different forms can use the same flow of steps to create the objects. In this case, a separate entity that called the ‘Builder’ do the object creation and the client can use the ‘Builder’ to create an object with any preference. Hence, the object can take different forms depending on the applied input parameters.

Problem Solved by the Builder Pattern

In general, we keep the object construction code such as instantiation and initialization within the object as a part of its constructor. This approach leads to the high coupling. It is suitable for small systems with lower object dependencies and lesser object representations or sub-classes.

When the roles and responsibilities get heavier for one object, the creation of that object becomes complex and messy. The object itself may get bulky, and low in modularity. At the same time object might need to take different forms to fulfil client requirements. Hence, it needs additional input parameters to get the required results. As a result, the number of constructor parameters increase. This may lead to the problem of ‘Telescoping Constructor’ pattern. It is an anti-pattern where the complexity caused due to the increased number of constructor parameters. Higher parameters lead problems like difficulty in selecting, remembering the correct order, and purpose of each parameter. In addition, it creates problems in selecting the suitable constructor for the required scenario.

Let’s think of a smoothie shop. You can buy different kinds of smoothies. Most customers like to drink chocolate smoothies, so if we take this to the programming world, you have a smoothie class and the class constructor contains the required parameters to make a smoothie,

However, you won’t see much sales if you sell this smoothie alone. A few customers like banana flavoured, some like the orange taste in the smoothie and some like to have peanut butter flavour. Therefore, you may have to create several different constructors to cater this need,

Likewise, the smoothie making becomes complex with the number of input parameters. The client may get confused with the large set of parameters and it will be difficult for client code to identify proper meaning and data types to add. Client code might get error prone and unreadable due to this telescoping constructor anti-pattern.

How to Solve the Problem

The builder pattern suggests an approach to remove the construction process from the object and hand over that process to a separate class. That separate class is ‘Builder’. Custom implementations can have more than one builder class to create different representations.

Builder Pattern Class Diagram Definition

Below diagram shows the template class diagram for the builder pattern. It includes four important classes as ‘Director’, ‘Builder’, ‘Concrete Builder’, and ‘Product’. Each one works together to achieve the builder pattern objective.

 

Builder Pattern Class Diagram
Builder Pattern Class Diagram

Builder

This is the component, which includes set of abstract methods to build the product object. This can be an interface or an abstract class. Complete implementation adds in the concrete builder class. The method ‘getPart()’ will return the final product object for the client. Each complex object requires the service of a ‘Builder’ class to generate object instances. Most of the times an interface or abstract builder class and several concrete builder classes.

Director

Director manages the object creation process using the Builder class and it will not directly create and assemble the final complex object. The method ‘construct()’ in ‘Director’ class includes a parameter to capture the specific concrete Builder class to generate the required object for the client. Then, the Director calls the suitable methods of the concrete builder class in the correct order to generate the final product. Concrete builder class will return the final product through the ‘getResult()’ method.

Director is the next level of separation in builder pattern. It removes the heavy burden on the client and takes care of the builder method set up and invocation on its account. Thus, director act as a dedicated object to invoke different builder methods to create the final object. Different client objects take the service of ‘Director’ object to full-fill their requirements.

Concrete Builder

This class implements the abstract methods and the rest of the functionalities to make the required representation of the product. It will construct and assembles the parts of the final product and provide the interface to retrieve the final product. This is the main component, which keeps track of the specific representation of the product.

Product

This is the complex object constructed using the concrete builder class which contains final user requested representation. This class defines complex object type and consists of multiple parts. Separate concrete builder classes create those final complex objects.

How does Builder Pattern work?

As in figure 1, ‘ConcreteBuilder’ class build the final required representation. The Client and the Builder hide the object construction process. Application Client needs to first instantiate a Director object and calls the Builder via the Director. Next, a suitable Builder object is passed to the Director object. After that, Director invokes the methods in Builder to create and initialize the suitable parts of the final Product. Finally, the Builder performs the execution to construct the required representation of the Product. Client keeps a reference to the Builder object and retrieves the created final Product.

Example for Builder Pattern

Let’s take the smoothie shop to build the example. Customers can have smoothies with different tastes and different ingredients. A customer has to select the ingredients and give it to the waiter to continue with the making.  Smoothies have different specifications according to the customer requirement. So, the final product will be a smoothie, but the representation of the smoothie will change according to the different parameters which used by each builder class.

In this example, there will be two different kinds of smoothies; those are banana with orange mix and banana, orange with date mix. Hence, we can identify two representations for the smoothie class and two builder classes will help us to make those two flavours of smoothies.

Below are the main components of the example smoothie making scenario.

  1. SmoothieBuilder
  2. BananaOrangeMixBuilder
  3. BananaOrangeDatesMixBuilder
  4. SmoothieDirector
  5. Smoothie

Let’s get to know the client class first. Because it contains the major instantiations and links to start the Builder pattern execution.  ‘SmoothieClient’ have to instantiate the Director and Builder objects and after that invoke ‘makeSmoothie’ method in ‘SmoothieDirector’ to perform the object creation steps. Finally, the client will call the ‘getSmoothie()’ method in ‘BananaOrangeMixBuilder’, Concrete Builder class as in the example to get the required final product.

SmoothieClient.java

SmoothieDirector.java

‘SmoothieBuilder’ is the template interface for the concrete Builder class. Each abstract method is overridden to achieve the specific functionality. Likewise, you can have a different flavour of the smoothie depending on the variations inside the methods.

SmoothieBuilder.java

‘BananaOrangeMixBuilder’ is the class to generate the specific mix or taste of the smoothie. This includes different implementations for each abstract method in the interface and returns the final smoothie object via ‘getSmoothie()’ method.

BananaOrangeMixBuilder.java

BananaOrangeDatesMixBuilder.java

‘Smoothie’ class represents the object features and functionalities of the object.

Smoothie.java

Sequence Diagram for the Example

 

Sequence Diagram for builder pattern
Sequence Diagram for builder pattern

When to Use the Builder Pattern?

  • When you want to create an object made up from several other objects
  • The creation process of the complex object should be independent of the object itself
  • Hide the creation logic and details from the client
  • When there are several representations of one object

Advantages of Builder Pattern

  • It improves modularity by separating the complex object creation from required object representation
  • Easy to modify and maintain since the construction process is isolated
  • Improves readability and testability
  • Reduces the object type and the coupling

Disadvantages Builder Pattern

  • This approach would be bit complex and bulky if the application is simple and consists of a small number of classes
  • Increase of classes to represent different forms of the same object would make performance overhead

Thus, it’s necessary to select builder pattern considering the scenario and object behaviours appropriately. Builder pattern is best when the construction process should be separated from the complex and poly-formic objects need to be created.

One thought to “Builder Pattern with Java examples”

Leave a Reply