Builder Design Pattern in Ruby

1. Definition

The Builder Design Pattern separates the construction of a complex object from its representation. It allows the same construction process to create different representations.

2. Problem Statement

Consider the scenario where you need to construct a complex meal, which may have multiple courses, each with different items. Directly constructing such a complex object in a single step can be cumbersome and may lead to a tangled constructor with numerous parameters.

3. Solution

The Builder Pattern suggests moving the construction logic out of the main class and delegating it to separate objects called builders. The original class, known as the "director", controls the construction process and specifies which steps should be taken.

4. Real-World Use Cases

1. Constructing complex meals in a restaurant system.

2. Building different types of reports with varying data and layouts.

3. Creating intricate 3D models in a gaming system.

5. Implementation Steps

1. Define an abstract Builder interface that specifies steps to construct parts of a product.

2. Create concrete builder classes for different variants of the product.

3. Define a director class that constructs the product using the builder's methods.

4. The client uses the director and the builder to produce the desired variant of the product.

6. Implementation in Ruby

# Step 1: Builder interface
class MealBuilder
  def add_starter; end
  def add_main_course; end
  def add_dessert; end
  def get_meal; end
end
# Step 2: Concrete builders
class VegMealBuilder < MealBuilder
  def initialize
    @meal = []
  end
  def add_starter
    @meal << "Veg Salad"
  end
  def add_main_course
    @meal << "Veg Curry"
  end
  def add_dessert
    @meal << "Fruit Salad"
  end
  def get_meal
    @meal.join(", ")
  end
end
class NonVegMealBuilder < MealBuilder
  def initialize
    @meal = []
  end
  def add_starter
    @meal << "Chicken Salad"
  end
  def add_main_course
    @meal << "Grilled Chicken"
  end
  def add_dessert
    @meal << "Ice Cream"
  end
  def get_meal
    @meal.join(", ")
  end
end
# Step 3: Director
class Chef
  def prepare_veg_meal(builder)
    builder.add_starter
    builder.add_main_course
    builder.add_dessert
    builder.get_meal
  end
  def prepare_non_veg_meal(builder)
    builder.add_starter
    builder.add_main_course
    builder.add_dessert
    builder.get_meal
  end
end
# Client code
chef = Chef.new
veg_builder = VegMealBuilder.new
puts chef.prepare_veg_meal(veg_builder)
non_veg_builder = NonVegMealBuilder.new
puts chef.prepare_non_veg_meal(non_veg_builder)

Output:

Veg Salad, Veg Curry, Fruit Salad
Chicken Salad, Grilled Chicken, Ice Cream

Explanation:

1. The MealBuilder class defines the abstract builder interface with methods to add different courses and get the meal.

2. VegMealBuilder and NonVegMealBuilder are concrete builders implementing the builder interface.

3. The Chef class acts as the director and uses a builder to construct meals.

4. The client code creates instances of the director and builders producing the desired type of meal.

7. When to use?

Use the Builder pattern when:

1. The algorithm for creating a complex object should be independent of the parts that make up the object and how they are assembled.

2. The construction process must allow different representations of the object being built.

3. The product's construction involves multiple steps, which might require different product configurations.


Comments