В попередній статті серії ми з вами розібрали Абстрактну Фабрику. Сьогодні ж розберемо патерн програмування – Будівельник. Цей шаблон також належить до групи Породжуючих шаблонів.

    Будівельник

    В цій статті розглянемо наступні питання:

    • означення шаблона,
    • приклад застосування,
    • коли застосовувати, його плюси і мінуси,
    • порівняємо даний шаблон із іншими породжуючим шаблонами,
    • а також розглянемо доцільність використання у мові програмування Python.

    Отже,

    Означення

    Даний шаблон розділяє процес створення складного об’єкта від його представлення, таким чином що в результаті одного і того ж процесу конструювання можна отримувати різні представлення об’єкта.

    Як завжди без прикладу нічого не зрозуміло, тому одразу на практиці розберемо патерн 😉

    Приклад

    Уявіть, що ви прийшли в МакДональдс і захотіли замовити дитяче меню (згадати дитинство 😉 – набір HappyMeal. Дане меню складається з основної страви, додаткової страви, напою та іграшки. Наприклад, це може бути: гамбургер, картапля фрі, кола і іграшка динозавр.

    Зауважте, що можливі різні варіанти кожного із елементів у даному дитячому наборі, але процес створення – однаковий. Незважаючи на те чи ви замовляєте чізбургер, курку чи гамбургер – процес однаковий:

    Працівник за стійкою керує усією командою, щоб зібрати докупи ваш набір – головну страву, додаткову та іграшку. Усі ці елементи попадають у сумочку. Напій йде окремо в стаканчику.

    Builder MacConalds

    Шаблон Будівельник: Клієнт – Розпорядник – Будівельник

    В даному прикладі ми (як клієнти, замовники) можемо замовити HappyMeal і вказати, які саме страви увійдуть до нього на місце основної страви та напою. Людина за стійкою (касир) отримує замовлення від нас (клієнта) та передає далі команді. Команда збирає докупи 4 елементи, базуючись на нашому замовленні. І ми (клієнти) отримуємо назад готовий набір.

    Тепер, якщо розбити по ролях відносно патерна Будівельник: ми виступаємо у ролі Клієнта (Client), Касир у ролі Розпорядника (Director – надає команди будівельнику), Команда закладу у ролі Абстрактного Базового Будівельника (Base Builder – може підготувати набір по будь-якому замовленню), а вже Команда, яка працює над конкретним замовленням – у ролі Конкретного Будівельника (Concrete Builder – готує конкретний набір по конкретному замовленні).

    В реалізації даного прикладу Будівельник допоможе нам виокремити процес створення замовлення від конкретного набору елементів, які Клієнт захотів отримати.

    А тепер розберемо детальніше усі ролі в патерні Будівельник:

    Основні ознаки та дійові особи патерна

    Патерн Будівельник визначає алгоритм поетапного конструювання складного продукта (об’єкта) від його зовнішнього представлення. Таким чином, що з допомогою одного і того ж алгоритма можна отримувати різні представлення даного продукта.

    Поетапне створення продукта означає його створення частинами. Після того, як побудована остання його частина, продукт можна використовувати.

    Для цього патерн Будівельник визначає алгоритм поетапного створення продукту в спеціальному класі Director (розпорядник), а відповідальність за координацію процесу збірки окремих частин продукта покладає на ієрархію класів Будівельника (Builder).

    В цій ієрархії базовий клас Будівельника (Builder) декларує інтерфейси (протокол) для побудови окремих частин продукту, а відповідні підкласи Будівельника (ConcreteBuilder) їх реалізують потрібним чином.

    Діаграма патерна Будівельник

    UML діаграма патерна Будівельник

    Основні ознаки патерна Будівельник:

    • вирішує проблему обробки подібних вхідних даних та потребу їх різних презентацій (вихідних даних);
    • ховає розбір вхідних даних в класі Розпорядника (Director);
    • декларує спільний стандартний протокол для створення всеможливих презентацій вихідних даних;
    • тримає усі кроки даного протоколу в інтерфейсі Будівельиника;
    • визначає підклас Будівельника для кожної із презентацій даних;
    • Клієнт створює об’єкт Розпорядника та Будівельник, і зв’язує їх між собою. А точніше передає Будівельник Розпоряднику;
    • Клієнт дає команду Розпоряднику – створити об’єкт;
    • Клієнт дає команду Будівельнику – повернути результат.

    Коли Використовується і порівняння з іншими породжуючими патернами

    Патерн Будівельник може допомогти у вирішенні наступного роду задач:

    • Якщо в системі існують складні об’єкти, створення яких за одну операцію є складно або неможливо. Потрібна поетапна побудова об’єктів з контролем результатів на кожному етапі.
    • Дані повинні мати кілька різних представлень. Класичний приклад. Маємо деякий вихідний документ у форматі RTF (Rich Text Format), який містить текст, зображення, інформацію про формат. І його потрібно представити у форматі Microsoft Word та звичайний текстом. Кожен з форматів і буде представленням даного документу.

    Деколи породжуючі патерни є взаємодоповнюючими. Будівельник може використовувати інші патерни, щоб створювати продукти. Абстрактна Фабрика, Будівельник та Прототип можуть використовувати Синглтон у своїй реалізації (більше про це у наступних статтях).

    Будівельник фокусується на конструкції складних об’єктів крок за кроком. В той час як Абстрактна Фабрика наголошує на створення сімейства об’єктів (складних або простих – неважливо). Будівельник повертає продукт (об’єкт) як кінцевий крок, а Абстрактна Фабрика повертає продукт одразу.

    Досить часто ваша програма може спочатку використовувати патерн Метод Фабрики (простіший та легший у кастомізації), а вже потім, із ускладненням вашого коду, переходити до використання Абстрактної Фабрики, Прототипа чи Будівельника, які надають більшої гнучкості в процесі створення нових об’єктів.

    Будівельник в мові Python

    Ну і нарешті, трохи коду. Коду на мові Python звичайно.

    Розберемо ще один приклад. Виробництво автомобілів. Покажемо на прикладі виробництва автомобілів двох різних типів: Джипа та легковика Нісан, застосування патерна Будівельник.

    Отже, код з детальними пояснюючими коментарями:

    Клас будівельника можна імплементувати кількома різними способами. Адже це абстрактний базовий клас, тому можна застосувати вбудовані можливості мови Python та скористатися метакласами і абстрактними методами:

    Проте серед пітон програмістів метакласи та абстрактні методи не надто популярні. Саме тому в основному прикладі я навів простіший варіант класу Будівельника.

    Як бачите, не зважаючи на те, який тип автомобіля ми будували, сам набір коду та команд залишився однаковим для Розпорядника. Нам просто треба було передати йому різні Будівельники, що отримати 2 різні типи автомобілів. В цьому і заключається основна суть даного патерна.

    Переваги патерна

    • Можливість контролювати процес створення складного продукта.
    • Можливість отримання різних представлень продукта і при цьому розмежовувати та уніфікувати процес побудови об’єкта від його представлення.

    Недоліки патерна

    • ConcreteBuilder та продукт, який він створює тісно зв’язані між собою, тому при внесенні змін в клас продукта швидше за все прийдеться відповідним чином змінювати клас ConcreteBuilder.

     ***

    От і все. Ще один породжуючий патерн оглянуто. Якщо у вас залишились питання – пишіть в коментах. Будемо разом розбирати.

    А які у вас є приклади використання даного шаблону проектування коду?

    Хочете більше дізнатись про веб-розробку та навчитись створювати веб-сайти використовуючи мову Python та веб-фреймворк Django? Гляньте дану пропозицію: