Builder Design Pattern
Prateek Mishra
Software Engineer at Google | ex. Microsoft, Walmart | Gold Medalist, IIIT Allahabad | XAT'24: 99.8
The builder pattern is a popular design pattern that is used to separate the construction of an object from its representation. It is particularly useful when the construction process is complex, or when there are multiple ways to create an object. This can be the case when dealing with complex objects that have a large number of attributes or configurations. Consider an example of a party planning application where users can plan their new year parties. Now all parties have some common attributes - location, time and occasion. However some parties can have additional attributes like theme, dresscode, food options, *cough* booze options *cough* etc. In such a scenario, it is important to have a way to create these complex objects in an organized and flexible way. The builder pattern can help by providing a clear and concise way to construct the object, allowing for better code reuse and flexibility.
Approach #1
One way to create the party planning application is to create a base class that represents a party, and then make different classes like BirthdayPartyForKids, BirthdayParty, NewYearPartyWithBooze, NewYearPartyWithoutBooze, BreakupParty, etc. extend this base class. We can then instantiate one of these classes as needed. However, this approach has the potential to quickly become unmanageable, as the number of subclasses can rapidly increase. The total number of sub-classes required would be 2^n (n is the number of optional attributes). For example, if there are four optional attributes, there could be as many as 16 subclasses. This approach may work for small applications, but it can become difficult to maintain as the number of subclasses grows.
Approach #2
Another way to create the party planning application is to create a common class and then use a parameter-heavy constructor that takes all the possible attributes as parameters. For the parameters that are not relevant, we can pass null. However, this approach can make the code difficult to read and understand because most of the parameters will often be unused, making it hard to determine which ones are relevant and which ones are not.
Approach #3
Another approach we can take is to create different constructors that take in different numbers of arguments. For example, we might have one constructor for BirthdayParties that takes only the location, time, occasion and mascot attributes, and another constructor for new year parties with booze that also takes the booze attribute. However, this approach also has its drawbacks. One issue is that there will be a large number of constructors catering to all the different combinations of the common attributes. Additionally, if two attributes have the same data type, it is not possible to create two constructors that take only one of those attributes as a parameter. This is because two methods with the same signature (i.e., the same number and type of parameters) cannot coexist in the same class, as there will be no way for the compiler to determine which one to choose.
Approach #4
We can also create a Party class and then use setters to set the required attributes. This approach is feasible, but it requires us to make the objects mutable in order to use the setters. One issue with this approach is that it can make the code less thread-safe. In general, making objects immutable is one way to ensure that code is thread-safe, because it prevents multiple threads from modifying the object at the same time. There are other approaches to achieving thread safety, such as using synchronization or using thread-safe data structures, but making objects immutable is often considered the easiest and most straightforward option.
Approach #5:
The builder pattern can be a useful solution in this case. With this approach, we create a class called the builder class, which is responsible for creating an object with the required parameters. The builder class has constructors for the required parameters, and setter-like methods for the optional parameters. These setter-like methods allow the developer to specify the values for the optional parameters, and the build method combines all the specified parameters to create the final object. Let's now look into the code:
Builder pattern highlights
Food for thought
Would this pattern still make sense if Java had named parameters?
Advantages
Disadvantages
When to use this pattern?
References
I took help from the following sources to write this article:
R&D Engineer-II @Nokia | Core Java | Spring Core | Spring Boot | Microservices | DSA | Docker | Kubernetes | Kafka | Contributing for building best software
2 个月Explained very well. Easy to understand
Founder of DearDiary |Software Engineer | MERN Stack Developer | C++ | JavaScript | Python | Continuous Learner | Innovative Application Builder | DSA
1 年thanks for this Article Prateek M. . For last one day i was struggling to find the answer that i found after understanding builder pattern that why can't i make setters instead of creating all this complex builder class and director class , and i found the answer from you thanks :))
Software Engineer at Google | ex. Microsoft, Walmart | Gold Medalist, IIIT Allahabad | XAT'24: 99.8
1 年Insightful : This is an article on the builder design pattern from the "Effective Java, 3rd Edition" by Joshua Bloch and is different from the builder design pattern given in the "Design Patterns: Elements of Reusable Object-Oriented Software" by Richard et al. Let's reserve a discussion on that for some other day.