← Назад к вопросам

Какие паттерны соответствуют принципам SOLID?

1.8 Middle🔥 201 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

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 принципы приводят к чистому, тестируемому и легко поддерживаемому коду. Используй их вместе с паттернами проектирования.

Какие паттерны соответствуют принципам SOLID? | PrepBro