Singleton
Одиночка — порождающий паттерн, гарантирующий, что у класса есть только один экземпляр, и предоставляющий глобальную точку доступа к нему.
classDiagram
direction BT
class DatabaseConnection {
- instance: DatabaseConnection
- connection_string: str
+ get_instance()
+ execute_query()
}
note for DatabaseConnection "В Python это часто реализуется
просто на уровне модуля."
В Java или C++ программисты тратят много усилий, чтобы создать "честный" Синглтон: блокируют потоки, используют private конструкторы и статические методы getInstance().
Модуль — это Синглтон!
В Python механизм импорта гарантирует, что код модуля выполняется только один раз. Если вы создадите объект в файле db.py и импортируете его в 10 разных местах, вы везде получите ссылку на один и тот же объект.
Пример, с которым вы работали: logging. Когда вы делаете logging.getLogger(), вы получаете ссылку на глобальный менеджер логов.
Плюсы:
- Экономия ресурсов (одно соединение с БД вместо ста).
- Глобальный доступ к настройкам или конфигурации.
Минусы:
- Глобальное состояние — это зло для тестов. Если один тест изменит Синглтон, второй тест может упасть.
- Сложнее отслеживать зависимости: "кто именно поменял эту настройку?".
Factory Method
Фабричный метод — паттерн, который определяет общий интерфейс для создания объектов, но позволяет подклассам решать, какой именно класс создавать.
classDiagram
direction BT
class Dialog {
+render()
+create_button() Button
}
class WindowsDialog {
+create_button()
}
class WebDialog {
+create_button()
}
class Button {
<<Interface>>
+on_click()
}
class WindowsButton {
+on_click()
}
class HTMLButton {
+on_click()
}
WindowsDialog --|> Dialog
WebDialog --|> Dialog
WindowsButton ..|> Button
HTMLButton ..|> Button
WindowsDialog ..> WindowsButton : Создает
WebDialog ..> HTMLButton : Создает
Суть паттерна: у нас есть код, например, Dialog.render(), который работает с кнопками, но он не знает, какие это кнопки — Виндовые или Веб. Он просто вызывает абстрактный метод create_button(), а конкретную кнопку создает подкласс.
Python-way:
В Python классы — это объекты первого класса. Нам часто не нужна сложная иерархия создателей. Мы можем просто передать класс как аргумент:
def create_dialog(button_cls): return button_cls()
Либо использовать @classmethod для реализации альтернативных конструкторов. Классический пример из стандартной библиотеки: datetime.fromtimestamp() — это фабричный метод, создающий объект даты из числа.
Abstract Factory
Абстрактная фабрика — это "Фабрика фабрик". Паттерн, позволяющий создавать семейства связанных объектов (Кнопка + Чекбокс + Скроллбар), не привязываясь к конкретным классам.
classDiagram
direction LR
class GUIFactory {
<<Interface>>
+create_button()
+create_checkbox()
}
class WinFactory {
+create_button()
+create_checkbox()
}
class MacFactory {
+create_button()
+create_checkbox()
}
class Application {
-factory: GUIFactory
+paint()
}
Application --> GUIFactory
WinFactory ..|> GUIFactory
MacFactory ..|> GUIFactory
Допустим, вы пишете кроссплатформенное приложение. Если вы запустились на Windows, все элементы (кнопки, окна, меню) должны быть в стиле Windows. Если на MacOS — в стиле MacOS.
Пример из жизни Python: pathlib
Когда вы пишете Path('.') в Python, вы используете фабрику.
Если вы запустите этот код на Windows, вам вернется объект WindowsPath.
Если на Linux — PosixPath.
Ваш код продолжает работать с абстрактным Path, не задумываясь, какая ОС под капотом.
Сильные стороны:
- Гарантирует, что продукты сочетаются друг с другом (вы не создадите Виндовую кнопку внутри Мак-окна).
- Изолирует код создания объектов от бизнес-логики.
Prototype
Прототип — паттерн, позволяющий копировать объекты, не вдаваясь в подробности их реализации (не завися от их классов).
classDiagram
direction LR
class Prototype {
<<Interface>>
+clone()
}
class Sheep {
-name
-dna_code
+clone()
}
Sheep ..|> Prototype
note for Sheep "Метод clone() создает
точную копию овечки."
В некоторых языках создание объекта через конструктор — дорогая операция (нужно лезть в базу, читать файлы и т.д.). Проще взять уже готовый настроенный объект и клонировать его.
Python-way: Модуль copy
В Python не нужно реализовывать интерфейс Cloneable. У нас есть стандартный модуль copy:
copy.copy(obj)— поверхностная копия (быстро, но вложенные объекты остаются общими).copy.deepcopy(obj)— полная рекурсивная копия (медленнее, но создает полностью независимый клон).
Используйте этот паттерн, когда:
- Инициализация объекта стоит дорого (запросы к БД).
- У вас есть сложный объект, который вы хотите сохранить "как шаблон" и штамповать его копии, меняя только пару полей.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ