31 серпня 2010 р.

"Патерн Вівторка" #4: Будівельник (Builder)

Уявіть, що ви володієте магазином (гаражом) по продажу ноутбуків в якому можна вибирати конфігурацію прямо біля каси (як піццу в піццерії). Вам слід створити систему, що дозволить легко будувати будь-яку конфігурацію ноутбука для будь-якого покупця.

Як ви можете це зробити легко?

БУДІВЕЛЬНИК

Будівельник (Builder) це породжувальний дизайн патерн, що дозволяє створити повний Продукт (Product) шляхом додавання певних частин, таких як процесор, пам'ять, жорсткий диск, батарея і т.д.

В кінці кінців ваш продавець балакає із клієнтом і запитується яку пам'ять він хоче і так далі. Або ж, якщо клієнт не дуже шарящий, продавець може запитатися "Ну вам той комп треба для шпільок? Яких?"
Іншими словами Вам потрібно знати наперед певні кроки щоб створити ноутбук. Ці кроки визначаються в Абстрактному Будівельнику (Abstract Builder).

    /* Abstract Builder */
    public abstract class LaptopBuilder
    {
        protected Laptop Laptop { get; private set; }
        public void CreateNewLaptop()
        {
            Laptop = new Laptop();
        }
        public Laptop GetMyLaptop()
        {
            return Laptop;
        }
        //mentioned steps to build laptop
        public abstract void SetMonitorResolution();
        public abstract void SetProcessor();
        public abstract void SetMemory();
        public abstract void SetHDD();
        public abstract void SetBattery();
    }

Якщо покупець відповідає "Ух, так! Я хочу шпілити... ууеех!" і у нього світяться очі, то Ви вже напоготові і маєте конкретну реалізацію для ігрового ноутбука:

    /* Concrete Builder */
    public class GamingLaptopBuilder : LaptopBuilder
    {
        public override void SetMonitorResolution()
        {
            Laptop.MonitorResolution = "1900X1200";
        }
        public override void SetProcessor()
        {
            Laptop.Processor = "Core 2 Duo, 3.2 GHz";
        }
        public override void SetMemory()
        {
            Laptop.Memory = "6144 Mb";
        }
        public override void SetHDD()
        {
            Laptop.HDD = "500 Gb";
        }
        public override void SetBattery()
        {
            Laptop.Battery = "6 lbs";
        }
    }

Але якщо Ваш покупець бізнесмен і переглядає презентації і звіти перелітаючи через атлантику:

    /* Concrete Builder */
    public class TripLaptopBuilder : LaptopBuilder
    {
        public override void SetMonitorResolution()
        {
            Laptop.MonitorResolution = "1200X800";
        }
        public override void SetProcessor()
        {
            Laptop.Processor = "Celeron 2 GHz";
        }
        public override void SetMemory()
        {
            Laptop.Memory = "2048 Mb";
        }
        public override void SetHDD()
        {
            Laptop.HDD = "250 Gb";
        }
        public override void SetBattery()
        {
            Laptop.Battery = "12 lbs";
        }
    }


Для того, щоб справитися із побудовою ноутбука базуючись на відповіді знадобиться директор (Director):

    /* Director */
    public class BuyLaptop
    {
        private LaptopBuilder _laptopBuilder;
        public void SetLaptopBuilder(LaptopBuilder lBuilder)
        {
            _laptopBuilder = lBuilder;
        }

        public Laptop GetLaptop()
        {
            return _laptopBuilder.GetMyLaptop();
        }

        public void ConstructLaptop()
        {
            _laptopBuilder.CreateNewLaptop();
            _laptopBuilder.SetMonitorResolution();
            _laptopBuilder.SetProcessor();
            _laptopBuilder.SetMemory();
            _laptopBuilder.SetHDD();
            _laptopBuilder.SetBattery();
        }
    }

А тепер глянемо на використання цього патерну:

            //Ваша система може мати багато конкретних будівельників
            var tripBuilder = new TripLaptopBuilder();
            var gamingBuilder = new GamingLaptopBuilder();
            var shopForYou = new BuyLaptop();//Директор
            shopForYou.SetLaptopBuilder(gamingBuilder);//Покупець каже, що хоче ігри шпілити
            shopForYou.ConstructLaptop();
            Laptop laptop = shopForYou.GetLaptop();//Ну то нехай бере що хоче!
            Console.WriteLine(laptop.ToString());

Вивід:

Laptop: 1900X1200, Core 2 Duo, 3.2 GHz, 6144 Mb, 500 Gb, 6 lbs

Ну знову мої старання в UML:



Простий як двері, корисний та геніальний патерн!

6 коментарів:

  1. Андрей, а чем ты таким замечательным пользуешся для рисования диаграмм?

    ВідповістиВидалити
  2. ах блин, вот для чего нужен планшет:)

    ВідповістиВидалити
  3. а можна діаграми зробити трохи чіткішими а то їх читати важко..

    ВідповістиВидалити
  4. в большинстве случаев (в реальной жизни) Builder используется "для упрощения конструирования сложных объектов" (it allows to hide construction complexity behind a convenient interface). Рекомендую обращать больше внимания на секцию Consequences в описаниях паттернов. Как показывает опыт - она ниболее полезная из всех

    ВідповістиВидалити