niedziela, 25 grudnia 2011

Design Pattern Builder

Wzorzec budowniczego (Builder) rozdziela proces tworzenia obiektu od jego reprezentacji dzięki czemu ten sam proces tworzenia obiektu może tworzyć różne reprezentacje.

Własnymi słowami: Builder umożliwia w łatwy sposób konstrukcję skomplikowanych obiektów. Builder otrzymuje informację tylko nt. tego jakiego typu obiekt chcemy stworzyć. Cały proces tworzenia obiektu jest ukryty przed użytkownikiem. Przydaje się zwłaszcza tam, gdzie kod tworzący dany komponent jest powtarzalny.
W przeciwieństwie do wzorca Abstract Factory każdy etap tworzenia obiektu przez Buildera jest modyfikowalny. W przypadku Abstract Factory otrzymujemy obiekt w jednym kroku.

Zobaczmy na diagram klas:

Klasy które występują w tym wzorcu:
Director - tworzy obiekt za pomocą interfejsu dostarczonego przez Builder-a
Builder - definiuje interfejs tworzenia składowych Product-u
ConcreteBuilder - spełnia 3 role:
  • Tworzy obiekty na podstawie interfejsu buildera
  • przechowuje instancję obiektu który wyprodukuje
  • udostępnia interfejs umożliwiający pobranie stworzonego obiektu
Product:
  • reprezentuje obiekt który chcemy stworzyć
  • ConcreteBuilder inicjuje wewnętrzną strukturę obiektu 
 Zobaczmy na przykład. Mamy warsztat samochodowy, który zajmuje się składaniem samochodów osobowych i quadów. Pojazdy te składają się z tych samych elementów, tylko w innej konfiguracji i ilości.
Zobaczmy najpierw na schemat klas:


W diagramie tym klasa VehicleBuilder reprezentuje Buildera. Klasy CarBuilder oraz QuadBuilder to konkretni budowniczy obiektów. WorkShop to obiekt utożsamiany z Direcotr. Vehicle to konkretny produkt, a klasy Wheel, Engine, Doors to składowe produktu.

Zobaczmy na sam kod:


Code:
using System;
using System.Text;

namespace BuilderSample
{
    class Program
    {
        static void Main()
        {
            VehicleBuilder builder = new CarBuilder();
            var workShop = new WorkShop();
            workShop.MakeVehicle(builder);
            builder.Vehicle.Specyfication();
            Console.WriteLine("--------------------------------------------");
            builder = new QuadBuilder();
            workShop.MakeVehicle(builder);
            builder.Vehicle.Specyfication();
        }
    }

    class WorkShop
    {
         public void MakeVehicle(VehicleBuilder vehicleBuilder)
         {
             vehicleBuilder.BuildDoor();
             vehicleBuilder.BuildEngine();
             vehicleBuilder.BuildWhell();
         }
    }

    public class Vehicle
    {
        public Engine Engine { get; set; }
        public Wheel Wheel { get; set; }
        public Doors Doors { get; set; }
        public string Type { get; set; }

        public Vehicle(string type)
        {
            Type = type;
        }

        public void Specyfication()
        {
            if (Engine == null)
            {
                throw new NullReferenceException("Engine can't be null");
            }
            if (Wheel == null)
            {
                throw new NullReferenceException("Whell can't be null");
            }
            if (Doors == null)
            {
                throw new NullReferenceException("Doors can't be null");
            }

            var specyficataion = new StringBuilder();
            specyficataion.Append("Type: ");
            specyficataion.Append(Type);
            specyficataion.AppendLine();
            specyficataion.Append("Door count: ");
            specyficataion.Append(Doors.Count);
            specyficataion.AppendLine();
            specyficataion.AppendLine("Whell specyfication: ");
            specyficataion.Append("Whell count: ");
            specyficataion.Append(Wheel.Count);
            specyficataion.AppendLine();
            specyficataion.Append("Whell producer: ");
            specyficataion.Append(Wheel.Producer);
            specyficataion.AppendLine();
            specyficataion.Append("Doors count: ");
            specyficataion.Append(Doors.Count);
            Console.WriteLine(specyficataion);
        }
    }

    public abstract class VehicleBuilder
    {
        protected Vehicle vehicle;

        public Vehicle Vehicle
        {
            get { return vehicle; }
        }

        public abstract void BuildEngine();
        public abstract void BuildWhell();
        public abstract void BuildDoor();
    }

    public class CarBuilder : VehicleBuilder
    {
        public CarBuilder()
        {
            vehicle = new Vehicle("Car");
        }

        public override void BuildEngine()
        {
            Vehicle.Engine = new Engine{CylindersCount = 4, Power = 100, Type = "Car engine"};
        }

        public override void BuildWhell()
        {
            Vehicle.Wheel = new Wheel{Count = 4, Producer = "Debica"};
        }

        public override void BuildDoor()
        {
            Vehicle.Doors = new Doors{Count = 4};
        }
    }

    public class QuadBuilder : VehicleBuilder
    {
        public QuadBuilder()
        {
            vehicle = new Vehicle("Quad");
        }

        public override void BuildEngine()
        {
            Vehicle.Engine = new Engine{CylindersCount = 2, Power = 50, Type = "Quad engine"};
        }

        public override void BuildWhell()
        {
            Vehicle.Wheel = new Wheel{Count = 4, Producer = "Debowe, quad type"};
        }

        public override void BuildDoor()
        {
            Vehicle.Doors = new Doors{Count = 0};
        }
    }

    public class Doors
    {
        public int Count { get; set; }
    }

    public class Wheel
    {
        public int Count { get; set; }
        public string Producer { get; set; }
    }

    public class Engine
    {
        public string Type { get; set; }
        public double Power { get; set; }
        public int CylindersCount { get; set; }
    }
}

Po uruchomieniu programu zobaczymy na ekranie następujący wynik:


2 komentarze: