Builder
Строитель — порождающий паттерн, который позволяет создавать сложные объекты пошагово. Строитель даёт возможность использовать один и тот же код строительства для получения разных представлений объектов.
classDiagram
direction LR
class Director {
-builder
+construct_sports_car()
+construct_suv()
}
class Builder {
<<Interface>>
+reset()
+set_engine()
+set_wheels()
+get_result()
}
class CarBuilder {
+set_engine()
+set_wheels()
+get_result()
}
class CarManualBuilder {
+set_engine()
+set_wheels()
+get_result()
}
Director --> Builder
CarBuilder ..|> Builder
CarManualBuilder ..|> Builder
Named Arguments vs Real Builder
В Java паттерн Builder часто используют, просто чтобы избавиться от конструкторов с 10 аргументами. В Python эта проблема решена на уровне языка с помощью именованных аргументов:
Car(color="red", engine="V8", gps=True) — это удобно и читаемо.
Но настоящий паттерн Builder нужен, когда процесс создания сложен и состоит из этапов. Лучший пример, который вы знаете — Django ORM:
User.objects.filter(is_active=True).exclude(role='guest').order_by('-date_joined')
Здесь QuerySet выступает в роли Строителя. Вы пошагово «настраиваете» будущий SQL-запрос. И только в самом конце, когда данные действительно нужны (метод get_result в паттерне или итерация в Django), объект «строится» и выполняется запрос к БД.
Lazy Initialization
Отложенная инициализация — это прием, когда мы откладываем создание тяжелого объекта или выполнение долгой операции до тех пор, пока результат нам действительно не понадобится.
Логика Lazy Initialization
flowchart LR
Start([Запрос атрибута]) --> Check{Уже создан?}
Check -- Да --> Return[Вернуть сохраненное значение]
Check -- Нет --> Calc[Выполнить тяжелую операцию]
Calc --> Save[Сохранить результат]
Save --> Return
В веб-разработке это критически важно. Представьте, что при запуске Django-проекта мы бы сразу загружали все данные из всех таблиц БД в память. Сервер бы стартовал час. Вместо этого мы используем ленивую загрузку.
Python-way: @cached_property
В Python этот паттерн реализуется невероятно элегантно через декоратор из стандартной библиотеки functools:
from functools import cached_property
class UserProfile:
@cached_property
def heavy_statistics(self):
print("Считаю сложную статистику...")
return 42
p = UserProfile()
print(p.heavy_statistics) # Выполнит код и сохранит 42
print(p.heavy_statistics) # Вернет сразу 42, не выполняя код
Сильные стороны:
- Ускоряет старт приложения (не делаем лишнюю работу сразу).
- Экономит ресурсы, если тяжелое поле так и не понадобилось пользователю.
Object Pool
Объектный пул — паттерн, который хранит набор уже инициализированных объектов, готовых к работе. Вместо того чтобы создавать объект с нуля (что долго), мы берем его из пула, используем и возвращаем обратно.
sequenceDiagram
participant Client
participant Pool
participant Database
Client->>Pool: Дай соединение!
alt В пуле есть свободное
Pool-->>Client: Вот, держи (Connection #1)
else Пул пуст
Pool->>Database: Создать новое соединение
Database-->>Pool: Connection #2
Pool-->>Client: Вот, держи (Connection #2)
end
Client->>Database: SQL Query...
Client->>Pool: Я всё, забирай (Connection #1)
В Python создание обычных объектов (строк, списков, классов) работает очень быстро, и пул для них не нужен (об этом заботится сборщик мусора). Но есть ресурсы, создание которых стоит очень дорого:
- Соединения с базой данных: Открытие TCP-соединения, авторизация, рукопожатие. Это занимает миллисекунды. Если открывать соединение на каждый запрос, сайт будет тормозить. Поэтому SQLAlchemy использует Connection Pool.
- Потоки и процессы: Создание нового процесса операционной системы — тяжелая операция. Поэтому мы используем
ThreadPoolExecutorили воркеры Celery/Gunicorn. Они создаются один раз при старте и потом просто обрабатывают задачи из очереди.
Итог: используйте пул, когда стоимость создания объекта («цена билета») слишком высока, чтобы платить её каждый раз.
Помните про GIL: пулы потоков хороши для I/O операций, а для вычислений лучше пулы процессов". Это покажет вашу техническую грамотность
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ