Принципы проектирования SOLID. Принцип единственной обязанности.

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

На самом деле самое страшное во всех принципах SOLID — это их аббревиатура. Сами принципы являются весьма понятными, хорошо сформулированными правилами проектирования программного обеспечения. Они позволяют писать легко поддерживаемый код со способностью к дальнейшему расширению. Такой код не просто проще поддерживать, но и гораздо дешевле.

Итак, ниже перечислены все пять принципов проектирования SOLID:

1). Принцип единственной обязанности (The Single Responsibility Principle — SRP);

2). Принцип открытости/закрытости (The Open/Closed Principle — OCP);

3). Принцип подстановки Барбары Лисков (The Liskov Substitution Principle — LSP);

4). Принцип разделения интерфейсов (The Interface Segregation Principle — ISP).

5). Принцип инверсии зависимостей (The Dependency Inversion Principle — DIP).

Данный урок посвящен непосредственно первому принципу SOLID.

S (The Single Responsibility Principle — SRP) — принцип единственной обязанности. Класс не должен иметь слишком много обязанностей, а лишь выполнять ту задачу, для которой он был создан. Также класс не должен принимать на себя чужие обязанности. По-другому этот принцип звучит как: «Существует лишь одна причина, которая может привести к изменению класса». Простой пример — логирование. Например, у нас есть класс Book, представляющий книгу:

Также в системе присутствует слой DAO, описанный в интерфейсе BookDAO и реализованный в классе BookDAOImpl. Назначение слоя DAO — доступ к нашим данным. то есть он выполняет такие операции, как добавление, удаление и получение объектов из базы. Для примера нам достаточно рассмотреть интерфейс класса BookDAO. Он достаточно прост:

Первые четыре метода относятся как раз к получению доступа к нашим сущностям. Но последний метод — log() осуществляет ведение журнала, записывая всю служебную информацию. Должен ли класс, задача которого — выполнение операций над сущностями выполнять подобную работу? Является ли этого его задачей? Вероятно, что нет. Для начала приведем шаблонную реализацию класса BookDAOImpl:

Теперь вспомним про сам принцип — лишь одна причина может привести к изменению класса. В нашей реализации первые четыре методы обладают высокой связностью в том плане, что они работают с одним хранилищем и выполняют одну общую задачу, поэтому вместе они — та самая единственная причина для изменения класса.  Метод log() же осуществляет совершенно другую работу и к тому же его реализация может изменяться(допустим мы будем логировать не просто в файл, а передавать куда-то данные по сети). Теперь у нас появилось сразу две причины для изменения класса.

Хорошим решением было поручить работу по логированию отдельному классу и просто включить его в класс BookDAOImpl, исключив из интерфейса класса метод log():

Теперь логирование поручено отдельному классу Logger, а наш класс BookDAOImpl снова имеет только одну обязанность — обеспечение доступа к данным. Таким образом, выполняя только одну задачу, он удовлетворяет первому принципу SOLID  — принципу единственной обязанности (SRP).

Крайним худшим случаем нарушения SRP является появление так называемых God Objects(божественных объектов), которые начинают выполнять все функции подряд. Например, в нашем примере ситуация бы еще больше усугубилась, если бы добавили в наш класс метод validate() и в нем бы начали реализовывать всю логику валидации. Помните о том, что каждый класс, который создается в вашей программе должен выполнять только одну поставленную перед ним задачу и не делать ничего сверх необходимого.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *