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

Что такое single responsibility?

2.0 Middle🔥 251 комментариев
#Архитектура и паттерны#ООП

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

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

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

Принцип единственной ответственности (Single Responsibility Principle)

Принцип единственной ответственности (SRP) — это первый и фундаментальный принцип SOLID, который гласит: "Каждый класс, модуль или функция должны иметь одну и только одну причину для изменения". Другими словами, класс должен быть ответственен лишь за одну конкретную задачу или аспект функциональности.

Суть принципа

SRP направлен на борьбу со "зловонным кодом" (code smell) под названием "Божественный объект" (God Object) — антипаттерном, когда один класс выполняет множество несвязанных задач. Такой код становится:

  • Сложным для понимания (нарушает принцип "разделения ответственности")
  • Трудным для тестирования (требует множество моков и сложных сценариев)
  • Хрупким (изменение в одной части может сломать другие)
  • Проблемным для повторного использования (привязан к множеству контекстов)

Практическая реализация на PHP

Рассмотрим нарушение SRP и его исправление.

❌ Пример нарушения принципа

class OrderProcessor {
    public function process(Order $order): void {
        // 1. Валидация заказа
        if (!$order->isValid()) {
            throw new InvalidOrderException();
        }
        
        // 2. Сохранение в базу данных
        $this->saveToDatabase($order);
        
        // 3. Отправка email-уведомления
        $this->sendConfirmationEmail($order);
        
        // 4. Генерация PDF-счета
        $this->generateInvoicePdf($order);
        
        // 5. Логирование
        $this->logProcessing($order);
    }
    
    private function saveToDatabase(Order $order): void { /* ... */ }
    private function sendConfirmationEmail(Order $order): void { /* ... */ }
    private function generateInvoicePdf(Order $order): void { /* ... */ }
    private function logProcessing(Order $order): void { /* ... */ }
}

Проблемы этого класса:

  • Изменение формата PDF счета потребует модификации OrderProcessor
  • Смена SMTP-сервера затронет этот же класс
  • Корректировка правил валидации также изменит OrderProcessor
  • У класса 5+ причин для изменения!

✅ Пример применения SRP

class OrderValidator {
    public function validate(Order $order): void {
        if (!$order->isValid()) {
            throw new InvalidOrderException();
        }
    }
}

class OrderRepository {
    public function save(Order $order): void {
        // Сохранение в БД
    }
}

class EmailNotifier {
    public function sendOrderConfirmation(Order $order): void {
        // Отправка email
    }
}

class InvoiceGenerator {
    public function generatePdf(Order $order): string {
        // Генерация PDF
        return $pdfContent;
    }
}

class OrderLogger {
    public function log(Order $order): void {
        // Логирование
    }
}

class OrderProcessor {
    public function __construct(
        private OrderValidator $validator,
        private OrderRepository $repository,
        private EmailNotifier $notifier,
        private InvoiceGenerator $invoiceGenerator,
        private OrderLogger $logger
    ) {}
    
    public function process(Order $order): void {
        $this->validator->validate($order);
        $this->repository->save($order);
        $this->notifier->sendOrderConfirmation($order);
        $this->invoiceGenerator->generatePdf($order);
        $this->logger->log($order);
    }
}

Ключевые преимущества применения SRP

1. Упрощение поддержки и модификации

  • Изменение логики отправки email затрагивает только EmailNotifier
  • Обновление правил валидации локализовано в OrderValidator
  • Каждый класс становится менее связанным (low coupling)

2. Улучшение тестируемости

// Тестирование становится более сфокусированным
public function testOrderValidator(): void {
    $validator = new OrderValidator();
    $invalidOrder = new Order([]);
    
    $this->expectException(InvalidOrderException::class);
    $validator->validate($invalidOrder);
}

3. Повышение переиспользуемости

  • EmailNotifier можно использовать для других типов уведомлений
  • InvoiceGenerator может работать с разными сущностями, не только с заказами

4. Упрощение онбординга новых разработчиков

  • Маленькие классы с единственной ответственностью проще понять
  • Четкие названия классов отражают их назначение

Как определить нарушение SRP

Класс нарушает SRP, если:

  • Его описание содержит союзы "и", "или", "а также"
  • Он зависит от несвязанных внешних изменений
  • При рефакторинге хочется "вынести часть функциональности"
  • Тесты класса проверяют множество несвязанных сценариев

Резюме

Принцип единственной ответственности — это не просто техническое требование, а философия проектирования, которая делает код:

  • Стабильным к изменениям
  • Понятным для коллег
  • Гибким для расширения
  • Надежным в эксплуатации

На практике SRP часто нарушается в угоду "быстрой разработке", но именно он является фундаментом для создания поддерживаемых и масштабируемых приложений. Как сказал Роберт Мартин: "SRP — это принцип, который проще всего понять, но сложнее всего применять правильно".