Какие паттерны соответствуют принципам SOLID?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
SOLID принципы и паттерны проектирования
SOLID — это пять принципов объектно-ориентированного программирования. Давайте рассмотрим каждый и связанные паттерны.
1. Single Responsibility Principle (SRP)
Класс должен иметь одну ответственность — одну причину для изменения.
Плохой пример:
class User:
def __init__(self, name, email):
self.name = name
self.email = email
def save_to_db(self):
# БД логика в User классе
pass
def send_email(self):
# Email логика в User классе
pass
def validate_email(self):
# Валидация в User классе
pass
Класс имеет три ответственности: управление данными, сохранение в БД, отправка email, валидация.
Хороший пример:
class User:
def __init__(self, name, email):
self.name = name
self.email = email
class UserRepository:
def save(self, user):
# Только сохранение в БД
pass
class EmailService:
def send(self, user):
# Только отправка email
pass
class EmailValidator:
def validate(self, email):
# Только валидация
pass
Каждый класс имеет одну ответственность.
Паттерны: Repository, Service, Validator.
2. Open/Closed Principle (OCP)
Класс должен быть открыт для расширения, но закрыт для модификации.
Плохой пример:
class PaymentProcessor:
def process(self, payment):
if payment.type == "credit_card":
# Обрабатываем кредитную карту
self.process_credit_card(payment)
elif payment.type == "paypal":
# Обрабатываем PayPal
self.process_paypal(payment)
elif payment.type == "bitcoin":
# Обрабатываем Bitcoin
self.process_bitcoin(payment)
# При добавлении нового типа платежа — модифицируем класс!
Хороший пример:
from abc import ABC, abstractmethod
class PaymentMethod(ABC):
@abstractmethod
def process(self, amount):
pass
class CreditCardPayment(PaymentMethod):
def process(self, amount):
# Логика кредитной карты
pass
class PayPalPayment(PaymentMethod):
def process(self, amount):
# Логика PayPal
pass
class BitcoinPayment(PaymentMethod):
def process(self, amount):
# Логика Bitcoin
pass
class PaymentProcessor:
def process(self, payment: PaymentMethod, amount):
payment.process(amount)
# При добавлении нового платежа — не модифицируем класс,
# добавляем новый класс наследник PaymentMethod
Паттерны: Strategy, Template Method, Decorator, Factory.
3. Liskov Substitution Principle (LSP)
Подклассы должны корректно замещать родительские классы. Если S подтип T, то объекты типа S должны работать везде где ожидается T.
Плохой пример:
class Bird:
def fly(self):
pass
class Eagle(Bird):
def fly(self):
return "Eagle soars"
class Penguin(Bird):
def fly(self):
raise Exception("Penguin cannot fly") # НАРУШЕНИЕ!
def make_bird_fly(bird: Bird):
return bird.fly() # Может выбросить исключение
Penguin нарушает контракт Bird.
Хороший пример:
class Bird(ABC):
pass
class FlyingBird(Bird):
@abstractmethod
def fly(self):
pass
class Eagle(FlyingBird):
def fly(self):
return "Eagle soars"
class Penguin(Bird):
def swim(self):
return "Penguin swims"
def make_bird_fly(bird: FlyingBird):
return bird.fly() # Безопасно
Паттерны: Strategy, Adapter, Decorator.
4. Interface Segregation Principle (ISP)
Клиенты не должны зависеть от интерфейсов, которые они не используют.
Плохой пример:
class Worker(ABC):
@abstractmethod
def work(self):
pass
@abstractmethod
def eat(self):
pass
class Robot(Worker):
def work(self):
return "Robot works"
def eat(self):
raise Exception("Robot doesn't eat") # НАРУШЕНИЕ!
Robot не нужен метод eat(), но он вынужден реализовать.
Хороший пример:
class Workable(ABC):
@abstractmethod
def work(self):
pass
class Eatable(ABC):
@abstractmethod
def eat(self):
pass
class Human(Workable, Eatable):
def work(self):
return "Human works"
def eat(self):
return "Human eats"
class Robot(Workable):
def work(self):
return "Robot works"
Паттерны: Adapter, Facade, Role Interface.
5. Dependency Inversion Principle (DIP)
Зависимости должны идти от конкретных классов к абстракциям (интерфейсам).
Плохой пример:
class UserRepository:
def save(self, user):
# Прямая зависимость от конкретной БД
pass
class UserService:
def __init__(self):
self.repository = UserRepository() # Жёсткая зависимость
def create_user(self, name, email):
user = User(name, email)
self.repository.save(user)
UserService зависит от конкретного UserRepository.
Хороший пример:
from abc import ABC, abstractmethod
class Repository(ABC):
@abstractmethod
def save(self, user):
pass
class UserRepository(Repository):
def save(self, user):
# Конкретная реализация
pass
class UserService:
def __init__(self, repository: Repository):
self.repository = repository # Инъекция зависимости
def create_user(self, name, email):
user = User(name, email)
self.repository.save(user)
# Использование
repository = UserRepository()
service = UserService(repository)
service.create_user("John", "john@example.com")
Паттерны: Dependency Injection, Service Locator, Factory.
Паттерны и SOLID
Repository Pattern → SRP + DIP
class UserRepository:
def save(self, user):
# Ответственность: только БД операции
pass
def find_by_id(self, id):
pass
Strategy Pattern → OCP + LSP
class Strategy(ABC):
@abstractmethod
def execute(self):
pass
class ConcreteStrategyA(Strategy):
def execute(self):
pass
class ConcreteStrategyB(Strategy):
def execute(self):
pass
Adapter Pattern → OCP + ISP
class OldInterface:
def old_method(self):
pass
class NewInterface(ABC):
@abstractmethod
def new_method(self):
pass
class Adapter(NewInterface):
def __init__(self, old_interface):
self.old = old_interface
def new_method(self):
return self.old.old_method()
Factory Pattern → DIP + OCP
class Factory:
def create_product(self, type):
if type == "A":
return ProductA()
elif type == "B":
return ProductB()
Observer Pattern → OCP
class Observable:
def __init__(self):
self.observers = []
def subscribe(self, observer):
self.observers.append(observer)
def notify(self):
for observer in self.observers:
observer.update()
Decorator Pattern → OCP + SRP
class Component(ABC):
@abstractmethod
def operation(self):
pass
class ConcreteComponent(Component):
def operation(self):
return "ConcreteComponent"
class Decorator(Component):
def __init__(self, component):
self._component = component
def operation(self):
return self._component.operation() + " + Decorator"
Лучшие практики
✅ Используй абстракции (интерфейсы)
def process(handler: PaymentHandler): # Абстракция
handler.process()
✅ Инъекция зависимостей
def __init__(self, repository: Repository):
self.repository = repository
✅ Один класс — одна ответственность
- User — только данные
- UserRepository — только БД операции
- UserService — только бизнес логика
✅ Используй композицию вместо наследования
class UserService:
def __init__(self, repository, validator, email_service):
self.repository = repository
self.validator = validator
self.email_service = email_service
❌ Избегай жёстких зависимостей
# Плохо
class Service:
def __init__(self):
self.repository = UserRepository()
# Хорошо
class Service:
def __init__(self, repository):
self.repository = repository
SOLID принципы приводят к чистому, тестируемому и легко поддерживаемому коду. Используй их вместе с паттернами проектирования.