niedziela, 8 lipca 2012

[Wzorce projektowe] Builder

Analogia z życia:

Przyrządzanie kawy składa się z kilku etapów : zaparzania, słodzenia i dodatków. Każdy z nich można przeprowadzić na różny sposób. Dodatkami mogą być mleko, śmietanka czy cynamon. Zamawiając kawę moglibyśmy za każdym razem podawać sposób parzenia i dodatki. Przeważnie jednak w menu mamy dostępne gotowe pozycje z opisanymi różnicami, które możemy zamówić.



Zastosowanie:

Wzorca konstruktora używamy przy tworzeniu złożonych obiektów. Skorzystanie z niego umożliwi oddzielenie logiki tworzenia obiektu, na którą składa się wiele etapów od konkretnych implementacji, gdzie za etapami idą konkretne dane. Zapewnia to reużywalnosć - ta sama logika jest w stanie stworzyć wiele obiektów. Warto pamiętać, że te obiekty różnią się danymi, a nie typami.

Zasada działania:

Stosuje się pewną hierarchię przy użyciu wzorca konstruktora. Klasa reżysera, z której API korzysta "reszta świata" ma za zadanie nadzorowanie całością. Przechowuje ona referencję do konkretnego buildera, wywołuje jego metody w odpowiedniej kolejności tak, aby stworzyć obiekt, a także udostępnia metodę, która zwraca instancję obiektu. Klasa abstrakcyjna buildera przechowuje referencję do produktu, udostępnia abstrakcyjne metody, które odpowiadają za etapy tworzenia produktu, a także metodę zwracającą instancję. Konkretne implementacje buildera nadpisują metody abstrakcyjne z klasy bazowej, gdzie zawarta jest konkretna logika przy tworzeniu produktu.


Przykład implementacyjny:

 public class Pizza
    {
        public string Name { get; set; }
        public int DoughHeight { get; set; }
        public List<MeatType> MeatTypes { get; set; }
        public List<CheeseType> CheeseTypes { get; set; }
        public List<string> Vegetables { get; set; }
    }

    public enum MeatType
    {
        Salami,
        Bacon,
        Ham
    }

    public enum CheeseType
    {
        Parmesan,
        Edam,
        Gouda
    }
public abstract class PizzaBuilder
    {
        protected Pizza pizza;

        public Pizza GetPizza()
        {
            return pizza;
        }

        public void CreateNewPizza()
        {
            pizza = new Pizza();
        }

        public abstract void SetName();
        public abstract void MakeDough();
        public abstract void PrepareCheese();
        public abstract void PrepareMeat();
        public abstract void PrepareVegetables();
    }
public class NapoletanaPizzaBuilder : PizzaBuilder
    {
        public override void SetName()
        {
            pizza.Name = "Napoletana";
        }

        public override void MakeDough()
        {
            pizza.DoughHeight = 10;
        }

        public override void PrepareCheese()
        {
            pizza.CheeseTypes = new List<CheeseType>(){CheeseType.Gouda};
        }

        public override void PrepareMeat()
        {
            pizza.MeatTypes = new List<MeatType>() { MeatType.Salami };
        }

        public override void PrepareVegetables()
        {
            pizza.Vegetables = new List<string>()
                                   {
                                       "Olives",
                                       "Paprika"
                                   };
        }
    }
public class SpararePizzaBuilder : PizzaBuilder
    {
        public override void SetName()
        {
            pizza.Name = "Sparare";
        }

        public override void MakeDough()
        {
            pizza.DoughHeight = 8;
        }

        public override void PrepareCheese()
        {
            pizza.CheeseTypes = new List<CheeseType>(){CheeseType.Edam};
        }

        public override void PrepareMeat()
        {
            pizza.MeatTypes = new List<MeatType>(){MeatType.Bacon};
        }

        public override void PrepareVegetables()
        {
            pizza.Vegetables = new List<string>()
                                   {
                                       "Mushrooms", "Onion", "Tomato", "Garlic"
                                   };
        }
    }
public class PizzaDirector
    {
        private PizzaBuilder _builder;

        public PizzaDirector(PizzaBuilder builder)
        {
            _builder = builder;
        }

        public void CreatePizza()
        {
            _builder.CreateNewPizza();
            _builder.SetName();
            _builder.MakeDough();
            _builder.PrepareCheese();
            _builder.PrepareMeat();
            _builder.PrepareVegetables();
        }

        public Pizza GetPizza()
        {
            return _builder.GetPizza();
        }
    }
class Program
    {
        static void Main(string[] args)
        {
            var maker = new PizzaDirector(new NapoletanaPizzaBuilder());
            maker.CreatePizza();
            Console.WriteLine(maker.GetPizza().Name);
            maker = new PizzaDirector(new SpararePizzaBuilder());
            maker.CreatePizza();
            Console.WriteLine(maker.GetPizza().Name);
        }
    }

Brak komentarzy:

Prześlij komentarz