Saturday, January 13, 2018

Design Pattern : Builder

The builder pattern is a design pattern that allows for the step-by-step creation of complex objects using the correct sequence of actions. The construction is controlled by a director object that only needs to know the type of object it is to create.
Builder pattern is another Gang of Four design pattern which belong to the creational design patterns family. The intent of the builder pattern is to separate the construction of a complex object from its representation. This pattern is used when complex object that need to be created is constructed by constituent parts that must by created in the same order or by using a specific algorithm.

Structural code example

The UML diagram below describes an implementation of the builder design pattern. This diagram consists of four classes:
  • Product: represents the complex object that is being built.
  • Builder: this is base class (or interface) for all builders and defines a steps that must be taken in order to correctly create an complex object (product). Generally each step is an abstract method that is overriden by concrete implementation.
  • ConcreteBuilder: provides implementation for builder. Builder is an object able to create other complex objects (products).
  • Director: represents class that controls algorithm used for creation of complex object. 
static class Program
{
    static void Main()
    {
        Builder b1 = new ConcreteBuilder1();

        Director.Construct(b1);
        var p1 = b1.GetResult();
        p1.Show();
    }
}

static class Director
{
    public static void Construct(Builder builder)
    {
        builder.BuildPartA();
        builder.BuildPartB();
    }
}

abstract class Builder
{
    public abstract void BuildPartA();
    public abstract void BuildPartB();
    public abstract Product GetResult();
}

class ConcreteBuilder1 : Builder
{
    private readonly Product _product = new Product();

    public override void BuildPartA()
    {
        _product.Add("Part A");
    }

    public override void BuildPartB()
    {
        _product.Add("Part B");
    }

    public override Product GetResult()
    {
        return _product;
    }
}

class Product
{
    private readonly List<string> _parts = new List<string>();

    public void Add(string part)
    {
        _parts.Add(part);
    }

    public void Show()
    {
        Console.WriteLine("Parts:");
        foreach (string part in _parts)
            Console.WriteLine("\t"+part);
    }
}

Real world example

Now let’s take a look at real world example. As a real world example I choose vehicle manufacturing. In this example I have created abstract class VehicleBuilder (Builder) which is a base class for all concrete builder classes (FordExplorerBuilder and LincolnAviatorBuilder). This class has method CreateVehicle which instantiates protected _vehicle field of type Vehicle (Product). Other methods are abstract and must be overriden by concrete builder implementation. This methods set properties of _vehicle. The last class VehicleCreator plays role as Director. It has constructor with one VehicleBuilder parameter and method CreateVehicle which controls steps for creation of object and filling it’s properties. Method GetVehiclereturns fully constructed Vehicle object.
class Program
{
    static void Main()
    {
        var vehicleCreator = new VehicleCreator(new FordExplorerBuilder());
        vehicleCreator.CreateVehicle();
        var vehicle = vehicleCreator.GetVehicle();
        vehicle.ShowInfo();

        Console.WriteLine("---------------------------------------------");

        vehicleCreator = new VehicleCreator(new LincolnAviatorBuilder());
        vehicleCreator.CreateVehicle();
        vehicle = vehicleCreator.GetVehicle();
        vehicle.ShowInfo();

    }
}

public abstract class VehicleBuilder
{
    protected Vehicle _vehicle;

    public Vehicle GetVehicle()
    {
        return _vehicle;
    }

    public void CreateVehicle()
    {
        _vehicle = new Vehicle();
    }

    public abstract void SetModel();
    public abstract void SetEngine();
    public abstract void SetTransmission();
    public abstract void SetBody();
    public abstract void SetDoors();
    public abstract void SetAccessories();
}
...
class FordExplorerBuilder : VehicleBuilder
{
    public override void SetModel()
    {
        _vehicle.Model = "Ford Explorer";
    }

    public override void SetEngine()
    {
        _vehicle.Engine = "4.0 L Cologne V6";
    }

    public override void SetTransmission()
    {
        _vehicle.Transmission = "5-speed M5OD-R1 manual";
    }

    public override void SetBody()
    {
        _vehicle.Body = "SUV";
    }

    public override void SetDoors()
    {
        _vehicle.Doors = 5;
    }

    public override void SetAccessories()
    {
        _vehicle.Accessories.Add("Car Cover");
        _vehicle.Accessories.Add("Sun Shade");
    }
}
...
class LincolnAviatorBuilder : VehicleBuilder
{
    public override void SetModel()
    {
        _vehicle.Model = "Lincoln Aviator";
    }

    public override void SetEngine()
    {
        _vehicle.Engine = "4.6 L DOHC Modular V8";
    }

    public override void SetTransmission()
    {
        _vehicle.Transmission = "5-speed automatic";
    }

    public override void SetBody()
    {
        _vehicle.Body = "SUV";
    }

    public override void SetDoors()
    {
        _vehicle.Doors = 4;
    }

    public override void SetAccessories()
    {
        _vehicle.Accessories.Add("Leather Look Seat Covers");
        _vehicle.Accessories.Add("Chequered Plate Racing Floor");
        _vehicle.Accessories.Add("4x 200 Watt Coaxial Speekers");
        _vehicle.Accessories.Add("500 Watt Bass Subwoofer");
    }
}
...
public class VehicleCreator
{
    private readonly VehicleBuilder _builder;

    public VehicleCreator(VehicleBuilder builder)
    {
        _builder = builder;
    }

    public void CreateVehicle()
    {
        _builder.CreateVehicle();
        _builder.SetModel();
        _builder.SetEngine();
        _builder.SetBody();
        _builder.SetDoors();
        _builder.SetTransmission();
        _builder.SetAccessories();
    }

    public Vehicle GetVehicle()
    {
        return _builder.GetVehicle();
    }
}
...
public class Vehicle
{
    public string Model { get; set; }
    public string Engine { get; set; }
    public string Transmission { get; set; }
    public string Body { get; set; }
    public int Doors { get; set; }
    public List<string> Accessories { get; set; }

    public Vehicle()
    {
        Accessories = new List<string>();
    }

    public void ShowInfo()
    {
        Console.WriteLine("Model: {0}",Model);
        Console.WriteLine("Engine: {0}", Engine);
        Console.WriteLine("Body: {0}", Body);
        Console.WriteLine("Doors: {0}", Doors);
        Console.WriteLine("Transmission: {0}", Transmission);
        Console.WriteLine("Accessories:");
        foreach (var accessory in Accessories)
        {
            Console.WriteLine("\t{0}",accessory);
        }
    }
}

No comments:

Post a Comment