Friday, January 3, 2025
Builder
Akash AmanUpdated: May 2025
📝 Brief
The Builder pattern is a creational design pattern 🏗️ that separates the construction of a complex object from its representation. This allows for creating different representations of an object using the same construction process.
❓ Problem
The Builder pattern solves two key problems:
-
🏗️ Managing complex object creation.
Complex objects often require detailed, step-by-step initialization of multiple fields and nested objects. This initialization is typically buried inside:
- A large, unwieldy constructor with too many parameters (commonly referred to as the "telescoping constructor" problem).
- Or worse, scattered across the client code, making it hard to read, maintain, or debug.
The Builder pattern organizes this process into manageable steps.
-
🔄 Creating different representations.
Sometimes, you need different versions of the same object with varying configurations. one might try creating multiple subclasses to cover all possible variations. This approach becomes unmanageable when:
- New features or parameters are introduced (e.g., adding a swimming pool or porch style to a house).
- Every combination of parameters leads to a growing hierarchy of subclasses.
The Builder pattern simplifies this by encapsulating the construction logic.
💡 Solution
Let’s explore how the Builder pattern achieves flexibility and clarity:
-
Define a Builder Interface:
The first step is to define a blueprint for building objects. This interface provides the structure for the steps needed to assemble an object. It ensures that all concrete builders follow the same process. -
Implement Concrete Builders:
Concrete builders implement the defined steps to construct specific object variations. This allows for creating different configurations or representations of the object. -
Direct the Building Process:
A director class orchestrates the building process. It ensures that builders follow the correct sequence of steps while allowing customization of the process. -
Simplify Object Construction:
The client code interacts with the director or builder to request specific configurations, abstracting away the complexity of the construction process.
📊 Blueprint
🛠️ Implementation & Analysis
Note:
-
A Standard Builder approach uses discrete methods to set object properties step by step, offering clarity and simplicity.
-
The Fluent Builder style chains method calls for a more concise and readable configuration. This approach is especially helpful when constructing objects with many configurable attributes.
-
Define Builder Interface: Create a base interface or abstract class with methods for setting the components of the object. This ensures that all concrete builders follow a consistent structure.
-
Concrete Builders: Implement the builder interface in classes tailored to create specific configurations or representations of the object. These builders encapsulate the construction logic.
-
Director Role: Introduce a director class to control the sequence of steps for creating the object. While optional, this ensures consistency when assembling complex objects.
For simpler use cases, the client can directly interact with the builder without requiring a director.
-
Client Code Integration: Use the builder or director to construct objects. This separates the construction logic from the object itself, improving code maintainability and flexibility.
Let's understand with an example.
In this example, we’ll implement a Meal Builder using the Builder pattern. The Builder pattern helps us construct complex objects step-by-step. Our goal is to create a Meal that consists of multiple items (like a Burger and a Drink) while keeping the construction process independent of the actual meal structure.
Step 1: Defining the Product
The "product" in the Builder pattern is the object being built. In our example, it’s the Meal.
AddItem: Adds an item to the meal.ShowItems: Displays all the items in the meal.
Step 2: Creating the Builder Interface
The Builder interface defines the steps required to build a meal. Each concrete builder will implement this interface to provide specific implementations for the steps.
AddBurgerandAddDrink: These methods define the steps for adding items to the meal.GetMeal: Returns the constructedMeal.
Step 3: Implementing Concrete Builders
Let’s create two concrete builders: VegMealBuilder for vegetarian meals and NonVegMealBuilder for non-vegetarian meals.
Step 4: Creating the Director (Optional)
The Director is responsible for managing the construction process. It uses a builder to construct a Meal step-by-step.
Step 5: Using the Builder Pattern in the Main Function
Now, let’s see the Builder pattern in action in the main function.
What Happens Here?
- We create two builders:
VegMealBuilderandNonVegMealBuilder. - The
Directororchestrates the construction process using the builder set viaSetBuilder. - The constructed meals are retrieved using
GetMealand displayed usingShowItems.
🧑💻 Putting It All Together
Here’s the complete Builder implementation:
⚖️ Pros & Cons
| 🚀 Pros | 👎🏻 Cons |
|---|---|
| You can be sure that a class has only a single instance. | Violates the Single Responsibility Principle. The pattern solves two problems at the time. |
🕒 When to Use
- Objects require numerous configuration steps or optional parameters.
- Different representations of an object are needed with minimal effort.
However, if your object is simple and doesn’t involve many parameters, the Builder pattern may add unnecessary complexity.