Попереднього разу ми з вами розібрали шаблон програмування Будівельник. Cьогодні ми продовжимо огляд породжуючих патернів і розглянемо так званий Фабричний Метод (англ. Factory Method).
У цій статті я наведу:
- означення Фабричного Методу
- розберемо приклад
- обговоримо коли застосовувати
- плюси та мінуси патерна
- і як завжди доцільність його застосування в мові Python
***
Означення
Фабричний Метод визначає інтерфейс для створення нового об’єкта, але рішення щодо типу створюваного об’єкту залишає підкласам даного інтерфейсу.
Іншими словами даний шаблон дозволяє класу відтерміновувати процес ініціації підкласам.
Якщо ви до кінця розібралися із шаблоном Абстрактної Фабрики, тоді розбіратися із даним шаблоном буде надзвичайно просто. Адже даний шаблон дуже подібний, але в той час як абстрактна фабрика фокусується більше не створення сімейства об’єктів, Фабричний Метод працює лише з одним об’єктом.
В даному шаблоні задіяні наступні дійові особи:
- Продукт (Product) – визначає базовий інтерфейс об’єктів, які ми створюватимемо абстрактним методом фабрики;
- Конкретний Продукт (Concrete Product) – реалізує інтерфейс Product, іншими словами це конкретні об’єкти типу Product;
- Фабрика (Factory) – базовий клас для конкретних фабрик, що містить фабричний метод; він визначає інтерфейс для конкретних фабрик;
- Конкретна Фабрика (Concrete Factory) – імплементує інтерфейс Фабрики, унаслідує та перевизначає її фабричний метод таким чином, щоб цей новий метод створював об’єкти Конкретного потрібного Продукту.
А тепер давайте до швидкого прикладу:
Приклад
Наведу коротенький приклад. Уявіть, що є два виробника іграшок. Іграшки пластикові різних форм: каченята, машинки, ляльки і т.д. Для виготовлення виробники обробляють спеціальний порошок для форм, створюють форми різних типів, і тоді заливають пластик у потрібні форми.
Таким чином ФОРМА визначає клас іграшки: машинка, каченя і т.д. Процес обробки такий самий, але взалежності від того, яку форму підставити отримуємо різні іграшки.
Якщо по ролях Фабричного Методу, то у даному прикладі маємо:
- Продукт – це пластик;
- Конкретний Продукт – це каченя, машинка, і т.д.;
- Фабрика – це конвеєр з виготовлення іграшок;
- Конкретна Фабрика – це форма для іграшки.
Плюси та коли використовувати
При розробці аплікації далеко не завжди можна наперед вирішити, які саме компоненти знадобляться. Зазвичай є лише загальне бачення того, що повинні робити компоненти, але реалізація функціоналу компонентів з уточненням їхніх можливостей виконується пізніше в ході роботи над проектом.
Дану проблему можна вирішити використовуючи інтерфейси. Але з інтерфейса неможливо створити об’єкт. Власне в такій ситуації необхідні об’єкти можна створювати з допомогою патерна Фабричний Метод.
Сильні сторони патерна:
- Плюсом Фабричного Методу є те, що він може повертати той самий інстанс класу кілька разів, або навіть може повертати підклас замість об’єкта конкретного типу. Таким чином, як і що повернути – справа лише метода фабричного. Інкапсуляція у повній своїй красі.
- Фабричний Метод робить дизайн вашої аплікації більш гнучким і лише трошки складнішим. Інші патерни зазвичай потребують нових класів, в той час як Фабричний Метод лише нової операції.
Мінуси
В даного шаблона є кілька обмежень:
- Це необхідність створення об’єкта Фабрика (або ще називають Creator) для того, щоб створити будь-який продукт з допомогою фабричного методу.
- Звичайно фабрика створена згідно даного шаблону не може виготовляти об’єктів з різними базовими класами. Усі мусять імплементувати однаковий інтерфейс. Для рішення даного обмеження рекомендую використовувати Абстрактну Фабрику натомість.
Застосування в мові Python
Знову ж таки наголошу, що даний патерн ніколи б не виник в середовищі програмування мови Python. Він, як і абстрактна фабрика, виник давніше, ще для обходу обмежень більш статичних мов програмування, як от C++.
В таких динамічних мовах як Python фабрики насправді не є потрібними зазвичай, оскільки класи є самі об’єктами (як і все інше в пітоні) і можуть передаватися напряму як аргументи.
Тому наведу приклади однієї і тієї ж програми двічі. Спочатку – класичний варіант згідно Фабричного Методу, а потім більш Pythonic вигляд:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# будемо виготовляти піцу # це наш Продукт, має свою ціну class Pizza(object): def __init__(self): self._price = None def get_price(self): return self._price # це конкретний продукт - різновид піци з грибами і шинкою # в нього конкретна ціна class HamAndMushroomPizza(Pizza): def __init__(self): self._price = 8.5 # піца VIP класу ;-) class DeluxePizza(Pizza): def __init__(self): self._price = 10.5 # гавайська, та що з ананасом, італійці від неї в шоці class HawaiianPizza(Pizza): def __init__(self): self._price = 11.5 # завод піци class PizzaFactory(object): # зверніть увагу на статичний метод декоратор # є тенденція використання classmethod замість нього # тоді не виникає проблем при унаслідуванні класу даної фабрики @staticmethod def create_pizza(pizza_type): # створюємо ту піцу яку нам сказали, через параметр pizza_type if pizza_type == 'HamMushroom': return HamAndMushroomPizza() elif pizza_type == 'Deluxe': return DeluxePizza() elif pizza_type == 'Hawaiian': return HawaiianPizza() # головний код програми # пробігаємось по усіх типах піци і, використовуючи фабрику # виготовляємо кожну з них if __name__ == '__main__': for pizza_type in ('HamMushroom', 'Deluxe', 'Hawaiian'): print 'Price of {0} is {1}'.format(pizza_type, PizzaFactory.create_pizza(pizza_type).get_price()) |
А тепер варіант, як би це написав я в мові Пітон, не знаючи нічого про патерни 😉 Цього разу без коментарів:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class Pizza(object): def __init__(self): self._price = None def get_price(self): return self._price class HamAndMushroomPizza(Pizza): def __init__(self): self._price = 8.5 class DeluxePizza(Pizza): def __init__(self): self._price = 10.5 class HawaiianPizza(Pizza): def __init__(self): self._price = 11.5 if __name__ == '__main__': for pizza_class in (HamAndMushroomPizza, DeluxePizza, HawaiianPizza): print 'Price of {0} is {1}'.format(pizza_class.__name__, pizza_class().get_price()) |
***
Тепер ви знаєте ще один породжуючий шаблон програмування. Використовувати його чи ні – звичайно на ваш розсуд. Все залежить від конкретної ситуації, задачі, мови програмування. В будь-якому разі ваш рівень піднявся, адже шаблони вважаються класикою і більшість досвідчених програмістів принаймні теоретично знайомі із більшістю шаблонами.
Наступного разу розберемо Прототип. Знайоме слово? 😉
Ви пробували даний шаблон програмування Фабричний Метод на практиці? Маєте зауваження до даної статті – коментуйте!
Хочете більше дізнатись про веб-розробку та навчитись створювати веб-сайти використовуючи мову Python та веб-фреймворк Django? Гляньте дану пропозицію:
де ж той Прототип? не вдається знайти статті про інші патерни на вашому сайті
ця серія ще в процесі. поки бракує багатьох шаблонів. планую вернутись до даної серії згодом
Віталій, а матеріал, який покладено в основу статті, це Ваш власний досвід?
Власний досвід описав в секції Застосування в мові Python. На практиці зазвичай використовую спрощений варіант патерна. Без додаткових фабрик. В пітоні не має особливої потреби на фабрики, як вже було зазначено в статті.