• ,

Пять основных принципов дизайна классов (S.O.L.I.D.) в Java

Классы — это блоки, из которых строится приложение Java. И если материал, из которого построено здание — некачественный, рано или поздно для такого здания настанут трудные времена. Так и в Java — некачественно написанные классы однажды могут привести к трудной ситуации в процессе работы приложения.

С другой стороны, хорошо разработанные и качественно написанные классы могут ускорить процесс кодирования и уменьшить количество ошибок.

В этой статье я перечислю пять основных принципов дизайна классов в объектно-ориентированном проектировании, которые следует иметь ввиду при написании кода. Сокращенно они называются S.O.L.I.D., и являются достаточно важными элементами написания классов.


Итак, как же расшифровывается S.O.L.I.D.:

  1. Single Responsibility Principle (Принцип единственной обязанности)
  2. Open Closed Principle (Принцип открытости/закрытости)
  3. Liskov’s Substitution Principle (Принцип подстановки Барбары Лисков)
  4. Interface Segregation Principle (Принцип разделения интерфейса)
  5. Dependency Inversion Principle (Принцип инверсии зависимостей)



Давайте рассмотрим эти принципы подробнее.

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

Суть принципа ясна из одной-единственной фразы:
На каждый объект должна быть возложена одна единственная обязанность.
Другими словами, вы должны писать, изменять и поддерживать класс только для одной цели. Если это модель класса, то она должна строго представлять собой одну функцию или действие. Это даст вам возможность вносить изменения в будущем, не боясь влияния изменений на другие объекты.

Каждый объект должен иметь одну обязанность и эта обязанность должна быть полностью инкапсулирована в класс. Все его сервисы должны быть направлены исключительно на обеспечение этой обязанности.

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

Принцип открытости/закрытости

Этот принцип достаточно емко характеризует следующее положение:
Программные сущности (классы, модули, функции и т.п.) должны быть открыты для расширения, но закрыты для изменения.
Что это значит? Это означает, что классы должны быть разработаны таким образом, что чтобы подстроить класс к данным конкретным условиям применения, достаточно расширить класс и переопределить некоторые функции. Таким образом, система должна быть гибкой и иметь возможность работы в изменяющихся условиях без изменения исходного кода. Если другие разработчики не в состоянии спроектировать желаемое поведение из-за ограничений в вашем классе, то вам следует изменить его. Это не значит, что любой может изменить всю логику вашего класса, но он/она должен иметь расширить класс и подстроить его для выполнения конкретной задачи.

Принцип подстановки Барбары Лисков

Этот принцип является вариацией принципа открытости/закрытости, о котором говорилось ранее. В нем говорится:
Объекты в программе могут быть заменены их наследниками без изменения свойств программы.
Это означает, что класс, разработанный на основании вашего базового класса путем расширения, должен работать в приложении без сбоев. То есть, если разработчик расширяет ваш класс и использует его в приложении, он не должен нарушать работу приложения или создавать фатальные ошибки для всего приложения.

Этого легко добиться, если помнить одно простое правило: Если ваш базовый класс делает строго одно дело, разработчик получит при использовании класса только одну проблему. Это может привести к некоторым ошибкам в одной области, но все приложение не будет работать неправильно.

Принцип разделения интерфейса

Характеризуется следующим утверждением:
Клиенты не должны быть вынуждены реализовывать ненужные методы, которые они не будут использовать

Принцип разделения интерфейсов говорит о том, что слишком «толстые» интерфейсы необходимо разделять на более маленькие и специфические, чтобы клиенты маленьких интерфейсов знали только о методах, которые необходимы им в работе. В итоге, при изменении метода интерфейса не должны меняться клиенты, которые этот метод не используют. Рассмотрим пример. Разработчик Алекс создал интерфейс «отчет», и добавил два метода: generateExcel() и generatedPdf(). Теперь клиент А хочет использовать этот интерфейс, но он намерен использовать отчеты только в PDF формате, а не в Excel. Устроит ли его такая функциональность?

Нет. Он должен будет реализовать два метода, один из которых по большому счету не нужен, и существует только благодаря Алексу — дизайнеру программного обеспечения. Клиент воспользуется либо другим интерфейсом, либо оставит поле для Excel пустым.

Так в чем же решение? Решение состоит в разделении существующего интерфейса на два более мелких. Один — отчет в формате PDF, второй — отчет в формате Escel. Это даст пользователю возможность использовать только необходимый для него функционал.

Принцип инверсии зависимостей
Многие знают слова, характеризующие этот принцип:
Зависимости внутри системы строятся на основе абстракций. Модули верхнего уровня не зависят от модулей нижнего уровня. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
Другими словами, следует разрабатывать программное обеспечение таким образом, что различные модули были автономными, и соединялись друг с другом с помощью абстракции. Классическое использование этого принципа можно наблюдать на примере Spring framework. В рамках Spring framework все модули выполнены в виде отдельных компонентов, которые могут работать вместе. Они выполнены настолько автономно, что могут использоваться в других программных модулях, кроме Spring framework с такой же легкостью.

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

Итак, это были пять основных принципов дизайна классов в объектно-ориентированном проектировании, которые следует иметь ввиду при написании кода. Удачи!

Исходная статья: 5 class design principles [S.O.L.I.D.] in Java
При переводе использовалась информация из Википедии
Переведено и озвучено: Ve4niY

1 комментарий

SergioShapoval
Вот здесь серия статей глубже раскрывает вопрос:
blog.byndyu.ru/2009/10/solid.html
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.