Sunday, May 10, 2009

Builder pattern in C#



Intent:
The Builder pattern separates the construction of a complex object from its representation, so that the same construction process can create different representations.
Non-Software Example:


Builder pattern can be found in Fast Food restaurants, while making a children’s meal. Typically children’s meal item consists of a main item like Burger, a side item like fries, a soft drink like Coke and a toy. Note that there can be variation in the content of the children's meal, but the construction process remains the same. Whether a customer orders a hamburger, cheeseburger, or chicken burger, the construction process of the meal is the same. The cashier at the counter directs the crew to assemble a main item, side item, and toy.



The Children’s Meal concept corresponds to the builder, which is an abstract Interface for creating parts of the Product object.
The restaurant crew corresponds to the ConcreteBuilder, as they will assemble the parts of the meal (i.e. make a hamburger).
The cashier corresponds to the Director, as the cashier will specify the parts needed for the children’s Meal, resulting in a complete Kid’s meal.
The children’s Meal package corresponds to the Product, as it is a complex object created via the Builder interface.

Benefits:


The construction process is separated from the representation.
The there is a finer control over the construction process and the internal structure of the finished product. Hence two different products from the same builder can be entirely different, but the construction process is the same.

Software Example & Explanation of Code:

Let us take the same above non-software example and try to convert it to a software example. Let us assume that we have got a requirement to build software for a restaurant which serves meals. Once of pages has to be designed for creating a Children’s meal. The Children meal either can be of Vegetarian type or Non-Vegetarian type. The UI (“Default.aspx”) is going to pass the meal type to be created and based on the meal type selected the Director of builder pattern (“Director.cs”) uses the concrete builders (“VegeterianMealBuilder.cs” and “NonVegeterianMealBuilder.cs”) to create the product object (Meal.cs).

UML:




Product: The product defines the type of object to be created by the Builder Pattern. Here in our case since we are creating a Meal object “Meal.cs” will be our product class.

Builder: The builder class defines all the steps that must be implemented to create a final product. Here in our case “MealBuilder.cs” abstract class is the builder and “Meal.cs” class is the product. The “GetMeal” method in the builder class returns the final product.
Concrete Builder: There may be any number of concrete builder classes. These classes inherit from the Builder class. Here in our case “MealBuilder.cs” is the builder class. “VegeterianMealBuilder.cs” and “NonVegeterianMealBuilder.cs” are the concrete builders. The concrete builder classes contain the complexity to build the objects.

Director: The director class controls the algorithm that generates the final product object. A director object is instantiated and its “MakeKidMeal” method is called. The method includes a parameter to capture the specific concrete builder object that is to be used to generate the product.

Following are the code for each of the classes

MealBuilder.cs

namespace BuilderPattern
{
public abstract class MealBuilder
{

public abstract void AddBurger();
public abstract void AddFries();
public abstract void AddDrink();
public abstract void AddToy();
public abstract void SetPrice();
public abstract Meal GetMeal();

}
}

NonVegeterianMealBuilder.cs

namespace BuilderPattern
{
public class NonVegeterianMealBuilder : MealBuilder
{
private Meal _NonVegMeal = new Meal();

public override void AddBurger()
{
_NonVegMeal.BurgerType = "Step 1 : One Chiken Burger";
}
public override void AddFries()
{
_NonVegMeal.FryType = "Step 2 : One Basket of Patato and Chicken Fry";
}
public override void AddDrink()
{
_NonVegMeal.DrinkType = "Step 3 : One Pepsi with out ICE ";
}

public override void AddToy()
{
_NonVegMeal.ToyType = "Step 4 : One Racing car toy ";
}

public override void SetPrice()
{
_NonVegMeal.Price = 4;
}
public override Meal GetMeal()
{
return _NonVegMeal;
}
}
}


VegeterianMealBuilder.cs

namespace BuilderPattern
{
public class VegeterianMealBuilder : MealBuilder
{
private Meal _VegMeal = new Meal();

public Meal Meal
{
get
{
throw new System.NotImplementedException();
}
set
{
}
}

public override void AddBurger()
{
_VegMeal.BurgerType = "Step 1 : One Vegiterian Burger";
}
public override void AddFries()
{
_VegMeal.FryType = "Step 2 : One Basket of Patato and Capsicum Fry";
}
public override void AddDrink()
{
_VegMeal.DrinkType = "Step 3 : One Coke with Ice and Lemon ";
}

public override void AddToy()
{
_VegMeal.ToyType = "Step 4 : One Soft toy ";
}

public override void SetPrice()
{
_VegMeal.Price = 2;
}
public override Meal GetMeal()
{
return _VegMeal;
}
}
}

Meal.cs

namespace BuilderPattern
{
public class Meal
{
private string _BurgerType;

public string BurgerType
{
get { return _BurgerType; }
set { _BurgerType = value; }
}
private string _DrinkType;

public string DrinkType
{
get { return _DrinkType; }
set { _DrinkType = value; }
}
private string _ToyType;

public string ToyType
{
get { return _ToyType; }
set { _ToyType = value; }
}
private string _FryType;

public string FryType
{
get { return _FryType; }
set { _FryType = value; }
}
private int _Price;

public int Price
{
get { return _Price; }
set { _Price = value; }
}
}
}

Now the director class

Director.cs

namespace BuilderPattern
{
public class Director
{
public void MakeKidsMeal(MealBuilder objMealBuilder)
{
objMealBuilder.AddBurger();
objMealBuilder.AddDrink();
objMealBuilder.AddFries();
objMealBuilder.AddToy();
objMealBuilder.SetPrice();
objMealBuilder.GetMeal();
}
}
}

The button click method can be represented as

Default.aspx

protected void btnPrint_Click(object sender, EventArgs e)
{
Meal objMeal = null;
Director objDirector = new Director();

if (ddlMealType.SelectedValue == "Veg Meal")
{
VegeterianMealBuilder objVegMeal = new VegeterianMealBuilder();
objDirector.MakeKidsMeal(objVegMeal);
objMeal = objVegMeal.GetMeal();
}
else if (ddlMealType.SelectedValue == "Non Veg Meal")
{
NonVegeterianMealBuilder objNonVegMeal = new NonVegeterianMealBuilder();
objDirector.MakeKidsMeal(objNonVegMeal);
objMeal = objNonVegMeal.GetMeal();
}

Response.Write("======================================================
");
Response.Write("Welcome To New Restruant
");
Response.Write("======================================================
");
Response.Write(objMeal.BurgerType+"

");
Response.Write(objMeal.FryType + "

");
Response.Write(objMeal.DrinkType + "

");
Response.Write(objMeal.ToyType + "

");
Response.Write("Total Meal price is $"+objMeal.Price.ToString() + " only

");
}

Happy Coding :)


The entire code for download is available at
http://www.csharppatterns.com/

References:
Non-Software examples of these patterns were published by Michael Duell in Object Magazine in July, 1997.

No comments: