Что такое принцип единственной ответственности (Single Responsibility Principle)?

Ответ

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

Проблемный пример (нарушение SRP): Класс Order занимается и бизнес-логикой заказа, и его сохранением в БД, и отправкой уведомлений.

class Order {
    public function calculateTotal() { /* ... */ }
    public function saveToDatabase() { /* ... */ }
    public function sendConfirmationEmail() { /* ... */ }
    // При изменении правил расчёта, схемы БД или формата email
    // придётся менять один и тот же класс.
}

Решение (соблюдение SRP): Разделяем ответственности на отдельные классы.

class Order {
    public function calculateTotal() { /* ... */ }
    // Отвечает только за данные и логику заказа.
}

class OrderRepository {
    public function save(Order $order) { /* ... */ }
    // Отвечает только за персистентность (работу с БД).
}

class NotificationService {
    public function sendOrderConfirmation(Order $order) { /* ... */ }
    // Отвечает только за отправку уведомлений.
}

Теперь, если изменится способ отправки email (например, добавится SMS), мы будем править только NotificationService. Изменение структуры таблицы в БД затронет только OrderRepository.

Преимущества следования SRP:

  • Упрощение тестирования: Легко протестировать OrderRepository отдельно от логики отправки писем.
  • Повышение читаемости и поддерживаемости: Классы становятся меньше и понятнее.
  • Снижение связанности: Изменения в одной части системы с меньшей вероятностью сломают другую.
  • Упрощение повторного использования: Класс NotificationService можно использовать для отправки уведомлений не только о заказах.

Ответ 18+ 🔞

Давай разберём этот принцип, а то он звучит как какая-то мантра из йоги, а на деле всё проще простого.

Представь себе чувака, который в жизни делает всё сам. Он и пельмени лепит, и машину чинит, и квартиру убирает, и отчёт начальнику пишет. Со стороны — молодец, универсальный солдат. А на деле? Как только начальник захочет отчёты в другом формате, наш герой весь свой график по уши, потому что ему теперь и пельмени недолепленные, и машина с незакрученной гайкой, и в квартире бардак. Одна причина для изменения (новый формат отчёта) — а последствия ебать на всю его деятельность. Вот это и есть нарушение SRP в жизни.

Так же и с классами. Если твой класс делает три разных дела, то любое изменение в одном из них заставляет тебя ковыряться во всём этом монстре. Доверия ебать ноль к такому коду, потому что поправил одно — сломал два других.

Смотри на примере, который ты привёл. Класс Order — это же пиздопроебина полная! Он и деньги считает, и в базу пишет, и письма рассылает. Представь, что тебе нужно поменять провайдера для отправки email (скажем, с Mailgun на SendGrid). Ты лезешь в класс заказа, рискуя сломать логику расчёта или, того хуже, запись в базу. Хуй с горы, а не архитектура.

А теперь правильный подход, где каждый класс — хитрая жопа, которая умеет делать только одно, но делает это хорошо.

  • Order — тупо данные заказа и логика их обработки (посчитать итог, применить скидку). Его дело — бизнес-правила.
  • OrderRepository — его единственная страсть — впендюрить данные в базу и достать их оттуда. Схема БД поменялась? Правим только его, и всем да похуй.
  • NotificationServiceманда с ушами, которая знает, как и куда слать уведомления. Захотел добавить SMS или Telegram? Изменяешь только этот сервис, не трогая ни заказы, ни базу.

В чём профит, спросишь?

  1. Тестирование — ебушки-воробушки. Хочешь проверить, правильно ли сохраняется заказ? Тестируешь OrderRepository в изоляции, подсовывая ему фейковую базу. Не нужно городить огород с моками для отправки писем.
  2. Читаемость. Открыл класс — и сразу понятно, за что он отвечает. Не нужно полчаса вникать, где тут заканчивается расчёт НДС и начинается коннект к SMTP-серверу.
  3. Меньше связанности. Классы общаются через чёткие интерфейсы. NotificationService вообще не знает, что такое база данных. Он получил объект заказа — отправил письмо. Всё. Если он сломается, то сломается только отправка писем, а не весь процесс оформления заказа.
  4. Переиспользование. Этот самый NotificationService можно взять и прикрутить к системе отзывов или оповещений о доставке. Потому что он не завязан на логику заказов, он просто умеет слать сообщения.

Короче, смысл в том, чтобы не создавать полупидоров, которые за всё в ответе, но ничего толком не умеют. Лучше сделать несколько узких специалистов, каждый из которых — мастер в своём деле. Тогда и жить проще, и код не превращается в ядерную вошь, которую страшно трогать.