Статьи

Нарушить принцип единой ответственности

Принцип единой ответственности (ПСП) не является абсолютным. Он существует для облегчения сопровождения кода и его читабельности. Но время от времени вы можете видеть решения, шаблоны, которые нарушают SRP и вроде бы в порядке. Это также верно и для других принципов, но на этот раз я хотел бы поговорить о SRP.

Синглтон ломает СРП

Самым старым и простым шаблоном, который нарушает SRP, является шаблон синглтона . Этот шаблон ограничивает создание объекта, так что существует один экземпляр определенного класса. Многие думают, что синглтон на самом деле является антипаттерном, и я также склонен полагать, что лучше использовать некоторый контейнер для управления жизненным циклом объектов, чем жестко кодируемые синглтоны или другие домашние фабрики. Анти-паттерн синглтона обычно происходит из-за того, что он нарушает SRP. Синглтон имеет две обязанности:

  1. Управление созданием экземпляра класса
  2. Сделайте то, что является оригинальной обязанностью класса

Вы можете легко создать синглтон, который не нарушает SRP, сохраняя первую ответственность, и отбрасывая вторую.

1
2
3
4
5
public class Singleton {
    private static final Singleton instance = new Singleton();
    public static Singleton getInstance() { return instance; }
    private Singleton() {}
}

но такого зверя не так много. Одиночки просты и обсуждаются более чем достаточно в блогах. Позвольте мне взглянуть на что-то более сложное, что нарушает SRP.

Мокито ломает СРП

Mockito — это фреймворк , который мы обычно используем в модульных тестах. Я предполагаю, что вы знакомы с насмешками и мокито. Типичный тест выглядит следующим образом:

1
2
3
4
5
6
7
8
import static org.mockito.Mockito.*;
List mockedList = mock(List.class);
when(mockedList.get(0)).thenReturn("first");
System.out.println(mockedList.get(0));
mockedList.add("one");
mockedList.clear();
verify(mockedList).add("one");
verify(mockedList).clear();

(образец взят со страницы Mockito, фактически смешивая два примера). Макет объекта создается с помощью статического вызова

1
List mockedList = mock(List.class);

и после этого используется для трех разных вещей:

  1. Настройте макет объекта для его насмешливой задачи.
  2. Веди себя как издевательство над издевательством над реальным объектом во время тестирования.
  3. Помощь в проверке использования макета.

Звонок

1
when(mockedList.get(0)).thenReturn("first");

устанавливает макет объекта. Звонки

1
2
3
System.out.println(mockedList.get(0));
mockedList.add("one");
mockedList.clear();

использовать основную ответственность за макет объекта и, наконец, линии

1
2
verify(mockedList).add("one");
verify(mockedList).clear();

действовать как проверка.

Это три разные задачи, а не одна. Я понимаю, что они тесно связаны друг с другом. Можно даже сказать, что это всего лишь три аспекта одной ответственности. Можно утверждать, что проверка использует только фиктивный объект в качестве параметра, а не функциональность фиктивного объекта. Дело в том, что фиктивный объект отслеживает его фиктивное использование и активно участвует в процессе проверки за кулисами. Хорошо, хорошо: все это может быть правдой, более или менее. Реальный вопрос: имеет ли это значение?

Ну и что?

Нарушается ли читаемость кода Mockito при обработке SRP таким образом? От этого страдает юзабилити API Mockito?

Ответ однозначно НЕТ на оба вопроса. Код настолько читабелен, насколько это возможно (хотя он более читабелен, чем многие другие проекты с открытым исходным кодом), но на него не влияет тот факт, что фиктивные объекты имеют множество обязанностей. Что касается API, вы можете даже сказать больше. Это читабельно и еще более удобно при таком подходе. Бывшие мокинг-фреймворки использовали строки для определения вызовов методов, таких как

1
2
mailer.expects(once()).method("send");
warehouse.expects(once()).method("hasInventory")

(фрагмент со страницы ), который менее читабелен и подвержен ошибкам. Опечатка в имени метода обнаруживается во время выполнения теста, а не во время компиляции.

Каков моральный дух? Не будь догматичным. Заботьтесь о принципах программирования, так как они помогут вам написать хороший код. Я не призываю никого игнорировать их каждый день. С другой стороны, если вы чувствуете, что некоторые принципы ограничивают вас и ваш код будет лучше без него, не стесняйтесь подумать о написании кода, который нарушает принципы. Обсудите это со своими сверстниками (программирование в любом случае является командной работой) и придите к выводу. Будет сделан вывод, что вы ошиблись, рассматривая возможность прерывания SRP в 90% случаев. В 10%, однако, вы можете прийти с блестящими идеями.

Ссылка: Откажитесь от принципа единой ответственности от нашего партнера по JCG Питера Верхаса в блоге Java Deep .