Шаблоны решения типовых задач
Четверо авторов легендарной книги:
Design Patterns (1994) — первая систематизация шаблонов проектирования
Готовое решение для типовой проблемы
Вы пишете одно и то же:
if model_type == 'nn':
train_nn(data)
elif model_type == 'tree':
train_tree(data)
# ...
Замените условия на объекты
class Trainer(ABC):
@abstractmethod
def train(self, data): pass
class NeuralTrainer(Trainer): ...
class TreeTrainer(Trainer): ...
trainer = trainers[config['type']]
trainer.train(data)
Разные алгоритмы — один интерфейс
def normalize(data, method):
if method == 'minmax':
return (data - min(data)) / (max(data) - min(data))
elif method == 'zscore':
return (data - mean(data)) / std(data)
class Normalizer(ABC):
@abstractmethod
def apply(self, data): pass
class MinMaxNormalizer(Normalizer): ...
class ZScoreNormalizer(Normalizer): ...
normalizer = MinMaxNormalizer()
normalized = normalizer.apply(data)
if/elifСоздание объектов без знания типа
model = None
if config['type'] == 'linear':
model = LinearModel()
elif config['type'] == 'nn':
model = NeuralModel()
class ModelFactory:
@staticmethod
def create(config):
if config['type'] == 'linear':
return LinearModel()
elif config['type'] == 'nn':
return NeuralModel()
model = ModelFactory.create(config)
registry = {
'linear': LinearModel,
'nn': NeuralModel
}
def create_model(name):
return registry[name]()
Кто-то изменился — другие узнают
def train_model():
model.fit(data)
log_training_result() # жёстко прописано
send_email_notification()
class EventManager:
def __init__(self):
self.listeners = []
def add_listener(self, listener):
self.listeners.append(listener)
def notify(self, event):
for l in self.listeners:
l.handle(event)
# Кто угодно может подписаться!
event_bus.add_listener(EmailNotifier())
event_bus.add_listener(Logger())
— События в FastAPI
— Callbacks в обучении модели
— Webhooks
Добавляем поведение без изменения класса
def predict(data):
print("Start prediction...") # логгирование
result = model.predict(data)
print("Done") # логгирование
return result
@log_execution
def predict(data):
return model.predict(data)
# или вручную
logged_predict = log_decorator(predict)
— @cache, @retry
— Middleware в FastAPI
— Декораторы в Python
Старое + новое = дружба
# Новый API требует JSON
result = new_service.process({"data": old_format}) # ошибка!
class OldToNewAdapter:
def __init__(self, old_service):
self.old_service = old_service
def process(self, new_data):
old_data = self.convert(new_data)
return self.old_service.run(old_data)
adapter = OldToNewAdapter(legacy_model)
adapter.process(json_input)
— API Gateway
— ORM (SQL ↔ объект)
— Форматы данных: CSV → Parquet
"Не применяйте паттерны ради паттернов.
Применяйте их, когда чувствуете боль."
Шаблоны архитектуры систем
Слои: UI → Use Cases → Domain → Data
# Пример структуры
app/
├── presentation/ # API, FastAPI
├── application/ # Use cases
├── domain/ # Модели, бизнес-логика
└── infrastructure/ # База, HTTP-клиенты
🔹 Часто используется в Django, Flask, FastAPI
Разделяем данные, отображение и логику
# Model
class User:
def save(self): ...
# View
def render_profile(user):
return f"{user.name}
"
# Controller
@app.route('/profile')
def profile():
user = User.get(1)
return render_profile(user)
🔹 Используется в вебе (Django, Rails)
Цепочка обработки: данные → фильтр → фильтр → результат
def clean_data(data):
return [x for x in data if x is not None]
def normalize(data):
total = sum(data)
return [x / total for x in data]
def encode_labels(data):
return [1 if x > 0.5 else 0 for x in data]
# Цепочка
result = encode_labels(normalize(clean_data(raw_data)))
🔹 Как пайплайн обучения или ETL
Посредник между компонентами (например, Message Broker)
# Производитель
queue.send("train_model", config)
# Потребитель
while msg := queue.receive():
if msg.topic == "train_model":
train(msg.data)
🔹 Kafka, RabbitMQ, Redis
Один сервер обслуживает множество клиентов
# Сервер (FastAPI)
@app.post("/predict")
def predict(data):
return model.predict(data)
# Клиент
requests.post("http://server/predict", json=input_data)
🔹 Основа всех веб-API
| Критерий | GoF | PoSA |
|---|---|---|
| Уровень | Классы и объекты | Система / Архитектура |
| Примеры | Strategy, Observer | MVC, Layers, Broker |
| Где применяется | Внутри сервиса | Между сервисами |
💡 GoF решает "как написать класс"
PoSA решает "как построить систему"