Design Patterns Part 4 : Builder Design Pattern
In this article we will be looking at another creational pattern which is the Builder Design Pattern. Before going into builder pattern, if you are new to design patterns I would recommend reading my first article by clicking here. I have done 3 different design patterns so far. The links will be given at the end of the article, feel free to check them if you want.
Now to the topic at hand, Builder design pattern. Builder design pattern comes under the Creational Design pattern. Just like with other creational pattern, builder design pattern will also help creating instances from objects an easier task. Imagine a class which has around 10 to 15 parameters. If you are to create custom constructors you will be creating a lot of constructors depending on the scenarios in which each attribute will be in use or not.
Lets take look at a scenario in a local restaurant, they will be serving a drink, kottu(Sri Lankan Food 🤗), rice and a desert. Users will also be able to ask for utensils or not. And all customers must order a type of drink at minimum. For this scenario we will be needing more than one constructor as orders will differ from customer to customer. One of the way to deal with this problem is to implement Telescopic constructors and another way is builder pattern. First I will show the telescoping constructors and after that I will explain why builder design pattern is the better choice.
Telescoping Constructor
One way to deal with complex objects is to use telescoping constructors. There are two ways we can implement a telescoping constructor.
First way is to get the parameter that is needed at minimum to create an instance of this class and then adding constructors with more parameters and calling the this()
constructor for the previous constructor’s parameters. The implementation can be seen from the below code snippet.
Note : The constructor that the
this()
loads will be depend the number of parameters that we parse in it. For example in the above example in the last parameter if I only parse in a single value the first constructor which takes in a drink will be called.
Another way to implement telescoping constructor is to have a base constructor which will take all parameters, and after that each constructor will call the constructor above them and pass in a default value for the parameter that will be empty(null for strings and objects and a default value for other primitives)until we a have a constructor that will only take one parameter. Look at the below code for the second type of telescoping constructor.
Note : Some of you must be thinking for utensils how a null value was passed. The reason is Boolean is a class type and boolean is object type. As I called the class type I am able to parse in null as a parameter.
Now you guys can see a problem with telescoping constrictors, we cannot have multiple constructor for the same data type. For example we can not create two constructors for the same data type. (If we take the above scenario, I cannot create a constructor that will take rice only as I already have a constructor that will take drink as a string). For this we can use getters and setters but this will make the fields mutable which may or may not be the best case depending on your scenario. And also creating constructors for a lot of parameters will be difficult and parsing in null values may cause NullPointerException.
Builder Design Pattern
As discussed above the telescoping constructors are not the best solution for complex objects. To create custom constructors for complex objects we can use the Builder Design Pattern. Builder design pattern will create an object step by step with the necessary fields that we pass. We can implement the Builder class as an Inner class of the object that we want to create.
Now lets take a look at Inner class implementation of Builder Design pattern for the above problem.
As seen from the above code the builder is defined as Static so there will be only one builder created at the memory. And inside the builder class we have private variables that are the same as the outer classes’. The Builder class has different methods that will set the value and return the current object.
Note : The methods inside the builder class are not setters. After setting the value we will be returning the current builder object.
If there are any parameters that are a must in the creation of the object, we can bound them by passing those values inside the default Builder constructor. In this scenario we are parsing in drink as, drink is a must for anyone that is ordering food.
The outer class will have a constructor that will take a Builder instance as a parameter and will create a new Instance, in this scenario a food instance will be created with the builder parameter. And the builder class will have a build method which will create the instance of the outer class with its current instance (this keyword in the parameter) and will return it back to the caller.
Now look at the below code for the execution of the main method.
As seen from above with the builder class I am able to create the object step by step by calling the required methods from the Builder class and finally I am calling the build method to return the Food instance from the Builder class. The output of the above code is shown below.
With the builder pattern I can also create an object that will take a drink and rice or drink and desert or drink, desert and utensils by running the following codes.
Food f = builder.rice("full").build();
Food f = builder.desert("faluda").build();
Food f = builder.desert("faluda").utensils(true).build();
Now you guys should be familiar with the builder design pattern, lets take a look at some key points of this pattern.
Key Points
- This pattern should be implemented when the object that we are going to create is a complex object with many parameters.
- With builder pattern it will be easier to add new parameters to the base object.
- The initial implementation of the Builder Pattern is a little bit complex as there is a lot of code to work with.
- This pattern can be implemented as an Inner class or as a separate class as well.(Inner class is considered as the best option)
- The StringBuilder class in java is implemented using the Builder design pattern.
REFERENCES
Design Pattern Part 1 : https://ravikugan-r.medium.com/design-patterns-part-1-singleton-b573c9d18ac0
Design Pattern Part 2 : https://ravikugan-r.medium.com/design-patterns-part-2-factory-design-pattern-b49c845f76ba
Design Pattern Part 3 : https://ravikugan-r.medium.com/design-pattern-part-3-prototype-design-pattern-67b87f6c9b56
Click here For the GitHub link of the above code implementation.
Check this video by Krishantha Dinesh as this article was based off of this video.