SOLID объектно ориентированное проектирование

Автор: | 24.07.2019

SOLID — акроним, выражающий принцип проектирования классов в ООП.

  • Single responsibility — принцип единственной ответственности
  • Open-closed — принцип открытости/закрытости
  • Liskov substitution — принцип замещения Барбары Лисков
  • Interface segregation — принцип разделения интерфейса
  • Dependency inversion — принцип инверсии зависимостей

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

Single responsibility — принцип единственной ответственности — применяется в тех случаях, когда какой-нибудь класс выполняет слишком много совершенно разных действий. Например, описывает какую-нибудь сущность, делает вставку значений в базу данных и генерирует отчеты. И всякий раз, при внесении изменений в какую-нибудь из этих операций, например, формат отчета изменился и т.п., будет меняться и класс. Также это приводит к усложнению тестирования. А принцип единственной ответственности гласит, что модуль программного обеспечения, будь то класс или метод, имеет лишь одну причину для изменения, и эта причина изменение ответственности модуля. Решением будет создать несколько классов, выделив каждому из них свою зону ответственности. В нашем примере это будут класс для описания сущности, класс для операций с базой данных и класс для создания отчетов.

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

Liskov substitution — принцип замещения Барбары Лисков — утверждает, что объекты в программе должны быть заменяемыми на экземпляры их подтипов без изменения правильности работы программы. К этому принципу можно также добавить — программируйте на уровне интерфейсов, а не конкретных реализаций. Отсюда возникает такое очень частое явление как upcasting классов.

Interface Segregation — принцип разделения интерфейса — говорит нам о том, что программный модуль не должен реализовывать методы интерфейса, которые он не использует. Много интерфейсов, специального назначения лучше, чем один интерфейс общего назначения. Применение данного принципа должно основываться на опыте и здравом смысле, чтобы в результате не получился код, содержащий много интерфейсов с одним методом.

Dependency inversion — принцип инверсии зависимостей — означает, что классы высокого уровня не работают непосредственно с классами низкого уровня, используя интерфейсы как абстрактный слой. Это значит, что инициализация объекта низкого уровня внутри класса высокого уровня не может быть выполнена с помощью оператора new. Для этого применяются шаблоны проектирования.

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

Перечислим еще несколько принципов относящихся к объектно ориентированному проектированию:

  • Программировать на уровне интерфейса, а не реализации
  • Не повторяться
  • Инкапсулировать то, что меняется
  • Принцип наименьшего знания (закон Деметры) — модуль не должен знать о деталях внутреннего устройства объекта, с которым работает
  • Голливудский принцип — компоненты высокого уровня (например, интерфейсы) определяют за компоненты низкого уровня, как и когда им подключаться в системе
  • Предпочитать композицию наследованию
  • Принцип делегирования
  • Применять шаблоны проектирования
  • Стремиться к слабой связанности взаимодействующих объектов