← Назад к вопросам
Расскажи как используешь ООП
3.0 Senior🔥 141 комментариев
#DevOps и инфраструктура#Django
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как я использую ООП в реальных проектах
15 лет опыта научили меня: ООП — инструмент, а не религия. Расскажу честно, как и когда я его применяю.
Принцип: ООП для моделей, функции для логики
Когда ООП ОБЯЗАТЕЛЕН
1. Моделирование реального мира
# Правильно: сущность User существует в реальности
class User:
def __init__(self, id: int, email: str, name: str):
self.id = id
self.email = email
self.name = name
def is_valid_email(self) -> bool:
return '@' in self.email
def full_name(self) -> str:
return self.name.upper()
# Использование
user = User(1, "alice@example.com", "Alice")
if user.is_valid_email():
print(f"Hello, {user.full_name()}")
2. Состояние с методами
# Класс имеет состояние И поведение
class BankAccount:
def __init__(self, balance: float):
self._balance = balance
def deposit(self, amount: float) -> None:
if amount <= 0:
raise ValueError("Сумма должна быть > 0")
self._balance += amount
def withdraw(self, amount: float) -> None:
if amount > self._balance:
raise ValueError("Недостаточно средств")
self._balance -= amount
@property
def balance(self) -> float:
return self._balance
# Использование
account = BankAccount(1000)
account.deposit(500)
account.withdraw(200)
print(account.balance) # 1300
Когда ООП ПЛОХОЙ выбор
Ошибка 1: Класс для всего
# ❌ Плохо: избыточное ООП
class MathUtils:
@staticmethod
def add(a, b):
return a + b
result = MathUtils.add(5, 3)
# ✅ Хорошо: просто функция
def add(a, b):
return a + b
result = add(5, 3)
Ошибка 2: Глубокая иерархия наследования
# ❌ Плохо: 5 уровней наследования
class Animal:
pass
class Mammal(Animal):
pass
class Carnivore(Mammal):
pass
class Cat(Carnivore):
pass
# ✅ Хорошо: используй композицию
class Animal:
def __init__(self, diet: str, habitat: str):
self.diet = diet
self.habitat = habitat
Мой реальный стек: SOLID принципы
Single Responsibility: одна обязанность
# ❌ Плохо: класс делает слишком много
class User:
def __init__(self, email: str):
self.email = email
def save_to_db(self):
# Сохранение в БД
pass
def send_email_verification(self):
# Отправка писем
pass
def calculate_premium_discount(self):
# Бизнес-логика
pass
# ✅ Хорошо: разделение ответственности
class User:
def __init__(self, email: str, name: str):
self.email = email
self.name = name
class UserRepository:
def save(self, user: User) -> None:
# Только сохранение в БД
db.insert(user)
class EmailService:
def send_verification(self, user: User) -> None:
# Только отправка писем
send_email(user.email, "Verify your account")
class PricingService:
def calculate_discount(self, user: User) -> float:
# Только бизнес-логика скидок
return 0.1 if user.is_premium else 0.0
Open/Closed: расширяемость без изменений
# ❌ Плохо: нужно менять класс для новых типов
class PaymentProcessor:
def process(self, method: str, amount: float):
if method == "credit_card":
# Логика для кредитной карты
pass
elif method == "paypal":
# Логика для PayPal
pass
# Каждый новый способ — изменение класса
# ✅ Хорошо: расширяемость через наследование
class PaymentMethod:
def process(self, amount: float) -> bool:
raise NotImplementedError
class CreditCardPayment(PaymentMethod):
def process(self, amount: float) -> bool:
# Логика для кредитной карты
return True
class PayPalPayment(PaymentMethod):
def process(self, amount: float) -> bool:
# Логика для PayPal
return True
class PaymentProcessor:
def __init__(self, method: PaymentMethod):
self.method = method
def process(self, amount: float) -> bool:
return self.method.process(amount)
# Использование
processor = PaymentProcessor(CreditCardPayment())
processor.process(100)
Dependency Injection: зависимости через конструктор
# ❌ Плохо: жёсткие зависимости
class UserService:
def __init__(self):
self.db = PostgreSQL() # Жёстко привязано к PostgreSQL
self.email = Gmail() # Жёстко привязано к Gmail
def register(self, email: str):
self.db.insert(email)
self.email.send("Welcome!")
# ✅ Хорошо: инъекция зависимостей
class UserService:
def __init__(self, db: Database, email_service: EmailService):
self.db = db
self.email = email_service
def register(self, email: str):
self.db.insert(email)
self.email.send("Welcome!")
# Использование
db = PostgreSQL()
email = Gmail()
service = UserService(db, email)
service.register("alice@example.com")
# Для тестов — подменяем на mock
db_mock = MockDatabase()
email_mock = MockEmailService()
service_test = UserService(db_mock, email_mock)
Мой реальный код: FastAPI приложение
from typing import Protocol
from dataclasses import dataclass
# 1. Модели данных (ООП для состояния)
@dataclass
class User:
id: int
email: str
is_active: bool = True
# 2. Интерфейсы (Protocol из typing)
class UserRepository(Protocol):
def get_by_id(self, id: int) -> User:
...
def save(self, user: User) -> None:
...
# 3. Реализация репозитория
class PostgresUserRepository:
def __init__(self, connection):
self.conn = connection
def get_by_id(self, id: int) -> User:
row = self.conn.execute(
"SELECT id, email, is_active FROM users WHERE id = ?",
(id,)
).fetchone()
return User(*row)
def save(self, user: User) -> None:
self.conn.execute(
"UPDATE users SET email = ?, is_active = ? WHERE id = ?",
(user.email, user.is_active, user.id)
)
# 4. Бизнес-логика (функции, не методы)
def activate_user(user: User, repo: UserRepository) -> None:
if user.is_active:
raise ValueError("User already active")
user.is_active = True
repo.save(user)
# 5. FastAPI эндпоинт (использование ООП)
from fastapi import FastAPI, Depends
app = FastAPI()
def get_repo() -> UserRepository:
return PostgresUserRepository(get_db_connection())
@app.post("/users/{user_id}/activate")
async def activate(user_id: int, repo: UserRepository = Depends(get_repo)):
user = repo.get_by_id(user_id)
activate_user(user, repo)
return {"status": "activated"}
Когда я ИЗБЕГАЮ ООП
1. Трансформация данных
# ❌ Плохо: класс-обёртка
class DataProcessor:
def normalize(self, data: list) -> list:
return [x.strip().lower() for x in data]
processor = DataProcessor()
result = processor.normalize(["HELLO", "WORLD"])
# ✅ Хорошо: просто функция
def normalize(data: list) -> list:
return [x.strip().lower() for x in data]
result = normalize(["HELLO", "WORLD"])
2. Утилиты и хелперы
# ❌ Плохо: статические методы в классе
class StringUtils:
@staticmethod
def reverse(s: str) -> str:
return s[::-1]
# ✅ Хорошо: функции в модуле
# utils.py
def reverse(s: str) -> str:
return s[::-1]
from utils import reverse
Реальный пример: обработка платежей
from abc import ABC, abstractmethod
from enum import Enum
class PaymentStatus(Enum):
PENDING = "pending"
COMPLETED = "completed"
FAILED = "failed"
class Payment(ABC):
def __init__(self, amount: float):
self.amount = amount
self.status = PaymentStatus.PENDING
@abstractmethod
def process(self) -> bool:
pass
def finalize(self, success: bool) -> None:
self.status = (
PaymentStatus.COMPLETED if success
else PaymentStatus.FAILED
)
class StripePayment(Payment):
def __init__(self, amount: float, token: str):
super().__init__(amount)
self.token = token
def process(self) -> bool:
try:
response = stripe.charge(self.token, self.amount)
self.finalize(response.success)
return response.success
except Exception as e:
self.finalize(False)
return False
# Использование
payment = StripePayment(100.0, "tok_visa")
success = payment.process()
print(f"Payment {payment.status.value}")
Итоговый совет
Используй ООП для:
- Моделирования сущностей (User, Product, Order)
- Инкапсуляции состояния (BankAccount)
- Интерфейсов и контрактов (PaymentMethod)
- Расширяемости через наследование
Используй функции для:
- Трансформации данных
- Утилит и хелперов
- Алгоритмов
- Один раз использующегося кода
Правило: Класс = существительное (User, Product, Account). Функция = глагол (process, calculate, validate).