Builder Pattern

Definition:

"Separate the construction of a object from its representation."

Separate the construction of a complex object from its representation. By doing so the same construction process can create different representations.

Description:

Builder Pattern provides the interface(builder interface) for creating object(product object) and steps to build the object. Director concrete class construct the object using defined steps(builder interface steps).

Difference between Factory Patterns Vs Builder Pattern?

Factory Pattern returns the product instance, where as Builder Pattern returns the product instance along with property values of a product.

What are you achieving with the help of Builder Pattern?

Able to create product instance and construct the properties of the product instance using step by step approach.

When to use?

  • Creation of complex object should be independent from how the object is build(represented).
  • Created object construction process shall have different representations.

Advantages:

  • Allows to vary a product’s internal representation(Provides way to have different representations for a product instance e.g., MealPlanInfo product instance can have representations like WeeklyMealPlan & MonthlyMealPlan).
  • Encapsulates code for construction and representation.
  • Provides control over steps of construction process(Provides the controlled steps to construct the product object)

Disadvantages:

Requires creating a separate ConcreteBuilder for each different type of Product(Need to create separate ConcreteBuilder class for each representation of a product).

Aim:

Collect the input required for generating different types of meal plan and use product object instance to generate different types of meal plan.

Use cases:

Day : 1
The system need below three inputs to generate the meal plan.
Required Input :

  1. NumberOfDays
  2. AvailableLunchMenu
  3. AvailableDinnerMenu

Day : 2
There is a change in Day : 1 requirement. The system needs to support generation of Breakfast menu as well.
Required Input :
  1. NumberOfDays
  2. AvailableBreakfastMenu
  3. AvailableLunchMenu
  4. AvailableDinnerMenu

The system need to generate different types(weekly meal plan and monthly meal plan) of meal plan using four required input.

Problem Statement:

  1. Passing required inputs to generate the meal plan using constructor with many parameter is difficult to maintain. In actual use case, passing four parameter may not look difficult to maintain. However, maintaining ten or more parameters in constructor is not good idea.
  2. Creating class instance, setting property values for a class with different representations(e.g., creating 'MealPlanInfo' class instance, setting property values for a class with WeeklyMealPlan & MonthlyMealPlan representations) in same place is not better approach.

Solution for Problem Statement:

  1. We can define the required input in Class and pass the class instance in method parameter. Adding 'N' number of properties is better idea as compared to have lengthy parameters in constructor.
    We are creating a class 'MealPlanInfo' and adding required input as properties of class for fixing Problem Statement #1.
  2. We can use Builder Pattern to create class instance, setting property values for a class with different representations using different classes is better approach for fixing Problem Statement #2.

Builder Pattern Program:

Builder Pattern

MealPlanInfo : (product) class with meal plan information properties.

MealPlanInputInfoBuilder : abstract class with steps to set MealPlanInfo (product ) class properties.

WeeklyMealPlanInputInfoBuilder : implements MealPlanInputInfoBuilder abstract class, creates product instance and set the property values of a product class.

MealPlanInputInfoDirector : concrete class has MealPlanInputInfoBuilder instance, define the steps to build MealPlanInfo (product) instance properties.


public class MealPlanInfo
{       
    public int NumberOfDays{ get; set; }
    public Dictionary<int, string> AvailableBreakfastMenu { get; set; }
    public Dictionary<int, string> AvailableLunchMenu { get; set; }
    public Dictionary<int, string> AvailableDinnerMenu { get; set; }
}

public abstract class MealPlanInputInfoBuilder
{
    public abstract void SetNumberOfDaysToGenerateMealPlan(DateTime StartDate, DateTime EndDate);
    public abstract void SetAvailableBreakfastMenu();
    public abstract void SetAvailableLunchMenu();
    public abstract void SetAvailableDinnerMenu();
    public abstract MealPlanInfo GetMealPlanInfoInstance();
}

public class WeeklyMealPlanInputInfoBuilder : MealPlanInputInfoBuilder
{
    MealPlanInfo weeklyMealPlanInfo;

    public WeeklyMealPlanInputInfoBuilder()
    {
        weeklyMealPlanInfo = new MealPlanInfo();
    }

    public override void SetNumberOfDaysToGenerateMealPlan(DateTime StartDate, DateTime EndDate)
    {
        weeklyMealPlanInfo.NumberOfDays = (EndDate - StartDate).Days;
    }

    public override void SetAvailableBreakfastMenu()
    {
        Dictionary<int, string> breakfastMenu = new Dictionary<int, string>();
        breakfastMenu.Add(1, "Scrumbled Egg");

        weeklyMealPlanInfo.AvailableBreakfastMenu = breakfastMenu;
    }

    public override void SetAvailableLunchMenu()
    {
        Dictionary<int, string> lunchMenu = new Dictionary<int, string>();
        lunchMenu.Add(1, "Fried Chicken");
        weeklyMealPlanInfo.AvailableLunchMenu = lunchMenu;
    }

    public override void SetAvailableDinnerMenu()
    {
        Dictionary<int, string> dinnerMenu = new Dictionary<int, string>();
        dinnerMenu.Add(1, "Grilled Atlantic Salmon");
        weeklyMealPlanInfo.AvailableDinnerMenu = dinnerMenu;
    }

    public override MealPlanInfo GetMealPlanInfoInstance()
    {            
        return weeklyMealPlanInfo;
    }
}

public class MealPlanInputInfoDirector
{
    DateTime _startDate, _endDate;
    MealPlanInputInfoBuilder _mealPlanInputInfoBuilder;        

    public MealPlanInputInfoDirector(MealPlanInputInfoBuilder mealPlanInputInfoBuilder, DateTime startDate, DateTime endDate)
    {
        _mealPlanInputInfoBuilder = mealPlanInputInfoBuilder;
        _startDate = startDate;
        _endDate = endDate;
    }       

    public MealPlanInfo ConstractMealPlanInputInfoInstance()
    {
        _mealPlanInputInfoBuilder.SetNumberOfDaysToGenerateMealPlan(_startDate, _endDate);
        _mealPlanInputInfoBuilder.SetAvailableBreakfastMenu();
        _mealPlanInputInfoBuilder.SetAvailableLunchMenu();
        _mealPlanInputInfoBuilder.SetAvailableDinnerMenu();

        return _mealPlanInputInfoBuilder.GetMealPlanInfoInstance();
    }
}


class BuilderClient
{
    static void Main(string[] args)
    {
        DateTime startDate = new DateTime(2017, 2, 1);
        DateTime endDate = new DateTime(2017, 2, 28);

        MealPlanInputInfoDirector director = new MealPlanInputInfoDirector(new WeeklyMealPlanInputInfoBuilder(), startDate, endDate);
        MealPlanInfo mealPlanInfo = director.ConstractMealPlanInputInfoInstance();

        Console.WriteLine("Constructed MealPlanInfo property values are NumberOfDays : {0}, AvailableBreakfastMenu Count : {1}, 
        AvailableLunchMenu Count : {2}, AvailableDinnerMenu Count :  {3} ", mealPlanInfo.NumberOfDays, mealPlanInfo.AvailableBreakfastMenu.Count, 
        mealPlanInfo.AvailableLunchMenu.Count, mealPlanInfo.AvailableDinnerMenu.Count);
        Console.ReadLine();
    }
}