Menu

Wzorce projektowe – Builder

18 kwietnia 2017 - .NET, Wzorce projektowe

W tej serii będę opisywał najpopularniejsze wzorce projektowe. Nie odkryję tu Ameryki, jednak posty te będą powstawać głównie dla utrwalenia wiedzy i możliwości szybkiego jej przejrzenia, a jeżeli komuś się to przyda to tym lepiej.

Na pierwszy ogień idzie jeden z podstawowych wzorców konstrukcyjnych a więc tytułowy „Builder”

Zalety: Za pomocą tego wzorca oddzielamy proces tworzenia obiektu od jego implementacji (za przykład mogą tu posłużyć wszelkiej maści konwertery potrafiące dać wiele formatów wynikowych).

Składowe:

  1. Builder – jest interfejsem abstrakcyjnym służącym do tworzenia obiektów.
  2. ConcreteBuilder 
    • Tworzy i łączy poszczególne składniki ze sobą.
    • Generuje i śledzi poszczególne wygenerowane składniki.
    • Udostępnia interfejs do pobrania gotowego obiektu.
  3. Director – tworzy obiekt za pomocą interfejsu klasy „Builder”.
  4. Product
    •  To on reprezentuje nasz wygenerowany złożony obiekt
    • Zawiera klasy definiujące składowe obiektu, oraz interfejsy do ich łączenia

 

Na diagramie przedstawia się to następująco:

 

Zastosowanie:

 

Czas na odrobinę kodu

  1. Tworzymy model naszego pożądanego obiektu (Product), który będzie tworzony przy użyciu Director’a implementującego interfejs Buildera
    namespace Builder.Product
    {
        public class Computer
        {
            private readonly string _computerOwner;
            public Cpu cpu { get; set; }
            public RamMemory ramMemory { get; set; }
            public HardDriveType hardDriveType { get; set; }
    
            public Computer(string computerOwner)
            {
                _computerOwner = computerOwner;
            }
    
            public override string ToString()
            {
                return string.Format("Owner: {0}\nCPU: {1}\nMemory: {2} GB\nHard Drive: {3}\n",
                    _computerOwner, cpu, (int)ramMemory, hardDriveType);
            }
        }
    }
  2. Kolej na nasz abstrakcyjny interfejs (Builder), który pomoże stworzyć nasz pożądany obiekt (Product).
    namespace Builder
    {
        public interface IComputerBuilder
        {
             void BuildCpu();
             void BuildRamMemory();
             void BuildHardDriveType();
             Computer GetComputer();
        }
    }
    

    Dla ułatwienia tego przykładu utworzyłem klasę Assembly

    namespace Builder.Model
    {
        public class Assembly
        {
            public enum Cpu
            {
                i3,
                i5,
                i7
            };
            
            public enum RamMemory
            {
                One = 1,
                Two = 2,
                Four = 4,
                Eight = 8
            }
    
            public enum HardDriveType
            {
                HDD,
                SSD,
                HYBRID
            }
        }
    
  3. Czas na Concrete Builder, który implementuje nasz interfejs (Builder). W moim wypadku są tą trzy klasy.
    namespace ConcreteBuilder
    {
        public class CheapComputerBuilder : IComputerBuilder
        {
            Computer _computer;
            public CheapComputerBuilder(string ownerName)
            {
                _computer = new Computer(ownerName);
            }
            public void BuildCpu()
            {
                _computer.cpu = Cpu.i3;
            }
    
            public void BuildHardDriveType()
            {
                _computer.hardDriveType = HardDriveType.HDD;
            }
    
            public void BuildRamMemory()
            {
                _computer.ramMemory = RamMemory.Two;
            }
    
            public Computer GetComputer()
            {
                return _computer;
            }
        }
    }
    
     public class ExpensiveComputerBuilder : IComputerBuilder
        {
            Computer _computer;
            public ExpensiveComputerBuilder(string computerOwner)
            {
                _computer = new Computer(computerOwner);
            }
            public void BuildCpu()
            {
                _computer.cpu = Cpu.i7;
            }
    
            public void BuildHardDriveType()
            {
                _computer.hardDriveType = HardDriveType.SSD;
            }
    
            public void BuildRamMemory()
            {
                _computer.ramMemory = RamMemory.Eight;
            }
    
            public Computer GetComputer()
            {
                return _computer;
            }
        }
    
      public class NormalPriceComputerBuilder : IComputerBuilder
        {
            Computer _computer;
            public NormalPriceComputerBuilder(string computerOwner)
            {
                _computer = new Computer(computerOwner);
            }
            public void BuildCpu()
            {
                _computer.cpu = Cpu.i5;
            }
    
            public void BuildHardDriveType()
            {
                _computer.hardDriveType = HardDriveType.HYBRID;
            }
    
            public void BuildRamMemory()
            {
                _computer.ramMemory = RamMemory.Four;
            }
    
            public Computer GetComputer()
            {
                return _computer;
            }
        }
    
  4. Director, odpowiada za prawidłową sekwencję budowania naszego obiektu.
    namespace Builder.Director
    {
        public class Manufacturer
        {
            public void BuildComputer(IComputerBuilder computerBuilder)
            {
                computerBuilder.BuildCpu();
                computerBuilder.BuildHardDriveType();
                computerBuilder.BuildRamMemory();
                computerBuilder.GetComputer();
            }
        }
    }
    
  5. Gotowy działający program
        class Program
        {
            static void Main(string[] args)
            {
                Manufacturer newManufacturer = new Manufacturer();
    
                // Lets have the Builder class ready
                IComputerBuilder computerBuilder = null;
    
                // Create a new cheap computer
                computerBuilder = new CheapComputerBuilder("Dave");
                newManufacturer.BuildComputer(computerBuilder);
                Console.WriteLine("A new Computer built:\n\n{0}", computerBuilder.GetComputer().ToString());
    
                // Create a new normal price computer
                computerBuilder = new NormalPriceComputerBuilder("Tom");
                newManufacturer.BuildComputer(computerBuilder);
                Console.WriteLine("A new Computer built:\n\n{0}", computerBuilder.GetComputer().ToString());
    
                // Create a new expensive computer
                computerBuilder = new ExpensiveComputerBuilder("Joe");
                newManufacturer.BuildComputer(computerBuilder);
                var computer = computerBuilder.GetComputer();
                Console.WriteLine("A new Computer built:\n\n{0}", computerBuilder.GetComputer().ToString());
            }
        }
    

A poniżej wynik finalny działania naszego programu

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *