Принципы SOLID — это 5 основных принципов/столпов, на которых стоит наше программное обеспечение. Как разработчики, мы не используем эти принципы должным образом. Иногда мы злоупотребляем ими, а иногда не используем их вовсе. Итак, в серии постов «Все о том, как быть S.O.L.I.D.» я пытаюсь рассказать об этих основных принципах дизайна на нескольких примерах.

5 принципов, которые SOLID пытается охватить:

  1. Единыйпринцип единой ответственности
  2. Открытыйпринцип закрытого пера
  3. Лисковпринцип подстановки
  4. Принцип разделения интерфейса
  5. Dпринцип инверсии зависимостей

В первой части серии мы увидим S принципов SOLID.

Принцип единой ответственности (SRP):

Прежде чем перейти к определению, давайте ответим на один вопрос. Можно ли есть ногами? Я надеюсь, что ответ на это НЕТ. Ваши ноги созданы для того, чтобы помогать вам ходить, и они будут делать только это. Каждая часть тела будет выполнять свою работу, работу только вокруг одной области ответственности.

Что касается определения, этот принцип гласит, что ваш модуль/класс должен иметь одну и только одну причину для изменения.

Давайте рассмотрим приведенный ниже пример и посмотрим, как этот принцип выглядит в действии.

public class NotificationService {
    public void sendEmail(String sender, String receiver, 
                          Content content) {
        ... // Logic to send email notification
    }
    public Content receiveEmail(String sender) {
        ... // Logic to receive email notification
    }
    public void sendSMS(String sender, String receiver, 
                        Content content) {
        ... // Logic to send sms notification
    }
    public Content receiveSMS(String sender) {
        ... // Logic to receive sms notification
   }
}

Что вы думаете о приведенном выше примере. Придерживается ли этот интерфейс SRP?
Нет. Может показаться, что класс придерживается SRP, поскольку он просто отправляет и получает уведомления. Но любые изменения уведомлений по электронной почте и SMS потребуют изменений в службе уведомлений. Наше определение SRP гласит, что у любого класса/модуля должна быть только одна причина для изменения. Здесь у нас есть 2 причины.
Давайте рефакторим приведенный выше код и посмотрим, что мы можем сделать.

public class NotificationService {
    private Map<NotificationType, Notification> notifications;
    public void sendNotification(NotificationType notificationType, 
                                 String sender, String receiver, 
                                 Content content) {
        ...
        Notification notification = notifications.get(notificationType);
        ...
        notification.send(sender, receiver, content);
        ...
    }
    public Content receiveNotification(NotificationType notificationType,
                                       String sender) {
        ...
        Notification notification = notifications.get(notificationType);
        ...
        Content content = notification.receive(sender);
        ...
        return content;
    }
}
public class EmailNotification implements Notification {
    ...
}
public class SMSNotification implements Notification {
    ...
}

Теперь служба уведомлений отправляет и получает уведомление (лучший интерфейс, чем раньше), но логика отправки и получения разных типов уведомлений разделена. Для изменений в уведомлениях по электронной почте вам не нужно вносить изменения в уведомления по смс.

Итак, теперь это соответствует SRP?
Ответ: «Пока что соответствует». Вы можете возразить, что классы XXXNotification по-прежнему имеют две обязанности: отправлять и получать уведомления, поэтому их также следует разделить. Хорошо следите за причинами, указывающими на такое разделение. Если вы видите, что ваш код становится неуправляемым или, возможно, вы добавляете разные условия для разных клиентов при отправке или получении, вы поймете, что пришло время снова применить SRP. Просто задайте себе один вопрос: есть ли у нас единственная причина измениться сейчас?

Примечание. Если вы не добавите к вопросу сейчас , вы можете злоупотребить этим принципом. Это чрезмерное использование приведет к большему количеству проблем, таких как дублирование кода в будущем.