Thursday, December 6, 2007

Builder Pattern

Suppose you had a series of objects that needed constructed, but your application needs to specialize how they are built. This is where the builder pattern comes into play. It handles performing the building of the necessary objects (also referred as the "product"); the builder class has that sole responsibility. The builder class also supports inheritance, which the product that the builder creates is usually involved in the inheritance scheme, meaning that the derived builder objects are actually building their related product object.

The builder pattern has a director that oversees the build process. The director has a reference to the builder(s) available and is responsible for invoking the correct method(s) in the builder. The builder has a common interface that all builders derive from and that the director knows about, and because of this, it can easily do its job. Inheritance plays a key, as the builder's interface is abstract, and the derived builder classes actually do the work of building an object. The resulting class that it builds can make use of inheritance to provide a more specific implementation. The builder class would be responsible for invoking the correct object.

It is possible that the builder/director relationship be dynamically created through the use of a configuration file, though that adds a lot of work to the software development process. More simplistically and realistically, this relationship is statically created through a constructor or an initialization method.

Non-software Example
Fast food restaurants to construct children's meals use this pattern. Children's meals typically consist of a main item, a side item, a drink, and a toy (e.g., a hamburger, fries, Coke, and toy car). Note that there can be variation in the content of the children's meal, but the construction process is the same. Whether a customer orders a hamburger, cheeseburger, or chicken, the process is the same. The employee at the counter directs the crew to assemble a main item, side item, and toy. These items are then placed in a bag. The drink is placed in a cup and remains outside of the bag. This same process is used at competing restaurants. [Michael Duell, "Non-software examples of software design patterns", Object Magazine, Jul 97, p54]

Another example for Builder pattern is a Computer Assembly. A computer is nothing but the bundling of various components like FDD, HDD, Monitor etc. But when an user buys a computer someone assemble all these components and given to us. Remember that here the building process is completely hidden from the client or user.

Remember that a project can contain one or more builders and each builder is independent of others. This will improves the modularity and makes the addition of other builders relatively simple. Since each builder constructs the final product step by step, we have more control over the final product that a builder constructs.

C# implementation
This real-world code demonstates the Builder pattern in which different vehicles are assembled in a step-by-step fashion. The Shop uses VehicleBuilders to construct a variety of Vehicles in a series of sequential steps.

using System;
using System.Collections;

namespace BuilderPattern{
// MainApp test application
public class MainApp
{
public static void Main()
{
// Create shop with vehicle builders
Shop shop = new Shop();
VehicleBuilder b1 =
new ScooterBuilder();
VehicleBuilder b2 =
new CarBuilder();
VehicleBuilder b3 =
new MotorCycleBuilder();
// Construct and display vehicles
shop.Construct(b1);
b1.Vehicle.Show();

shop.Construct(b2);
b2.Vehicle.Show();

shop.Construct(b3);
b3.Vehicle.Show();
// Wait for user
Console.Read();
}
}
// "Director"

class Shop
{
// Builder uses a complex series of steps
public void Construct(VehicleBuilder vehicleBuilder)
{
vehicleBuilder.BuildFrame();
vehicleBuilder.BuildEngine();
vehicleBuilder.BuildWheels();
vehicleBuilder.BuildDoors();
}
}

// "Builder"

abstract class VehicleBuilder
{
protected Vehicle vehicle;

// Property
public Vehicle Vehicle
{
get{ return vehicle; }
}

public abstract void BuildFrame();
public abstract void BuildEngine();
public abstract void BuildWheels();
public abstract void BuildDoors();
}

// "ConcreteBuilder1"

class MotorCycleBuilder : VehicleBuilder
{
public override void BuildFrame()
{
vehicle =
new Vehicle("MotorCycle");
vehicle["frame"] = "MotorCycle Frame";
}

public override void BuildEngine()
{
vehicle["engine"] = "500 cc";
}

public override void BuildWheels()
{
vehicle["wheels"] = "2";
}

public override void BuildDoors()
{
vehicle["doors"] = "0";
}
}

// "ConcreteBuilder2"

class CarBuilder : VehicleBuilder
{
public override void BuildFrame()
{
vehicle =
new Vehicle("Car");
vehicle["frame"] = "Car Frame";
}

public override void BuildEngine()
{
vehicle["engine"] = "2500 cc";
}

public override void BuildWheels()
{
vehicle["wheels"] = "4";
}

public override void BuildDoors()
{
vehicle["doors"] = "4";
}
}

// "ConcreteBuilder3"

class ScooterBuilder : VehicleBuilder
{
public override void BuildFrame()
{
vehicle =
new Vehicle("Scooter");
vehicle["frame"] = "Scooter Frame";
}

public override void BuildEngine()
{
vehicle["engine"] = "50 cc";
}

public override void BuildWheels()
{
vehicle["wheels"] = "2";
}

public override void BuildDoors()
{
vehicle["doors"] = "0";
}
}

// "Product"

class Vehicle
{
private string type;
private Hashtable parts = new Hashtable();

// Constructor
public Vehicle(string type)
{
this.type = type;
}

// Indexer (i.e. smart array)
public object this[string key]
{
get{ return parts[key]; }
set{ parts[key] = value; }
}

public void Show()
{
Console.WriteLine("\n---------------------------");
Console.WriteLine("Vehicle Type: {0}", type);
Console.WriteLine(" Frame : {0}", parts["frame"]);
Console.WriteLine(" Engine : {0}", parts["engine"]);
Console.WriteLine(" #Wheels: {0}", parts["wheels"]);
Console.WriteLine(" #Doors : {0}", parts["doors"]);
}
}
Output