Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# SRP vs SoC: Разница между принципами проектирования
SRP — Single Responsibility Principle
SRP — один из 5 принципов SOLID, который гласит: класс должен иметь только одну причину для изменения.
Это означает, что каждый класс/модуль должен отвечать за одну функциональную ответственность.
Пример SRP
# ❌ Нарушение SRP — класс отвечает за множество задач
class User:
def __init__(self, name: str, email: str):
self.name = name
self.email = email
def save_to_database(self):
"""Сохранение в БД"""
db.insert('users', {'name': self.name, 'email': self.email})
def send_email(self, subject: str, body: str):
"""Отправка email"""
smtp.send(self.email, subject, body)
def generate_report(self):
"""Генерация отчета"""
return f"User Report: {self.name} - {self.email}"
def validate_email(self) -> bool:
"""Валидация email"""
return '@' in self.email
# Причины для изменения User:
# 1. Логика базы данных изменилась
# 2. SMTP конфиг изменился
# 3. Формат отчета изменился
# 4. Правила валидации email изменились
✅ Правильно — каждый класс одна ответственность
from typing import Protocol
from abc import ABC, abstractmethod
class User:
"""Отвечает только за данные пользователя"""
def __init__(self, name: str, email: str):
self.name = name
self.email = email
class UserRepository:
"""Отвечает за сохранение в БД"""
def save(self, user: User) -> None:
db.insert('users', {'name': user.name, 'email': user.email})
def find_by_email(self, email: str) -> User:
row = db.query('users', {'email': email})
return User(row['name'], row['email'])
class EmailService:
"""Отвечает за отправку email"""
def send(self, to: str, subject: str, body: str) -> None:
smtp.send(to, subject, body)
class EmailValidator:
"""Отвечает за валидацию"""
@staticmethod
def is_valid(email: str) -> bool:
return '@' in email and '.' in email.split('@')[1]
class UserReportGenerator:
"""Отвечает за генерацию отчетов"""
@staticmethod
def generate(user: User) -> str:
return f"User Report: {user.name} - {user.email}"
# Использование:
user = User("John", "john@example.com")
if EmailValidator.is_valid(user.email):
UserRepository().save(user)
EmailService().send(user.email, "Welcome", "Hello!")
print(UserReportGenerator.generate(user))
Причины для изменения каждого класса: только 1
Userменяется если изменится структура пользователяUserRepositoryменяется если меняется БДEmailServiceменяется если меняется SMTPEmailValidatorменяется если меняются правила валидацииUserReportGeneratorменяется если меняется формат отчета
SoC — Separation of Concerns
SoC — это более широкий принцип, который гласит: разделяй программу на отдельные разделы (concerns), каждый из которых решает отдельную задачу.
SoC фокусируется на архитектурном уровне, а не только на классах.
Пример SoC в архитектуре
# Слоистая архитектура (Layered Architecture)
# 🎨 PRESENTATION слой — что видит пользователь
# (Views, API endpoints, Controllers)
from fastapi import APIRouter
router = APIRouter(prefix="/api/v1/users")
@router.post("/register")
def register_user(name: str, email: str):
# Только парсирование входа и форматирование выхода
result = create_user_use_case.execute(name, email)
return {"id": result.id, "email": result.email}
# ✨ APPLICATION слой — бизнес-логика
# (Use Cases, Service Layer)
class CreateUserUseCase:
def __init__(self, repository: UserRepository, validator: EmailValidator):
self.repository = repository
self.validator = validator
def execute(self, name: str, email: str) -> User:
if not self.validator.is_valid(email):
raise ValueError("Invalid email")
user = User(name, email)
self.repository.save(user)
return user
# 📦 DOMAIN слой — бизнес-сущности
# (Entities, Domain Logic)
class User:
def __init__(self, name: str, email: str):
if not name or not email:
raise ValueError("Name and email required")
self.name = name
self.email = email
# 🔧 INFRASTRUCTURE слой — деталі реалізації
# (Database, External APIs, Logging)
class PostgresUserRepository(UserRepository):
def save(self, user: User):
db.execute(
"INSERT INTO users (name, email) VALUES (@name, @email)",
{"name": user.name, "email": user.email}
)
Separation of Concerns:
- Presentation не знает о БД
- Application не знает как отображается в UI
- Domain не зависит от того, какая БД
- Infrastructure легко заменяется
Ключевые различия
| Аспект | SRP | SoC |
|---|---|---|
| Уровень | Микро (классы, методы) | Макро (архитектура, слои) |
| Фокус | Одна ответственность на класс | Разделение функциональности по областям |
| Пример | UserRepository vs EmailService | Presentation vs Business Logic vs DB |
| Масштаб | Внутри модуля | Между модулями и слоями |
| Цель | Упростить тестирование класса | Упростить поддержку всей системы |
| Связь | SRP — частный случай SoC | SoC — более общий принцип |
# Пример: SoC включает SRP
# SoC: DOMAIN слой отделён от DB слоя
class Post: # DOMAIN
def __init__(self, title: str, content: str):
self.title = title
self.content = content
def is_valid(self) -> bool:
return len(self.title) > 0 and len(self.content) > 0
class PostRepository: # INFRASTRUCTURE
def save(self, post: Post):
pass # SQL логика здесь
# SRP внутри каждого: Post только валидирует,
# PostRepository только сохраняет
Итого
- SRP — убирает множественные ответственности из одного класса
- SoC — убирает "свалку" логики и разделяет её по слоям/модулям
- SRP более конкретный и практический
- SoC более философский и архитектурный
- Оба работают вместе для создания чистой и поддерживаемой кодовой базы