Введение

Проектируя систему, мы занимаемся моделированием, а значит решаем инженерную задачу. Мы строим гипотезу о том, каковы отношения между сущностями в этой системе.

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

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

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

Принцип открытости-закрытости (Open-Closed Principle, OCP) помогает исключить такую проблему. Согласно ему модули должны быть открыты для расширения, но закрыты для изменения.

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

Основная цель принципа — помочь разработать проект, устойчивый к изменениям, срок жизни которых превышает срок существования первой версии проекта.

Модули, которые удовлетворяют OCP:

  • открыты для расширения — их функциональность может быть дополнена с помощью других модулей, если изменятся требования;
  • закрыты для изменения — их код менять нельзя (можно лишь исправлять ошибки).

Конечно, всегда есть изменения, которые невозможно внести, не изменив код какого-то модуля — никакая система не может быть закрыта на 100%. Поэтому при проектировании важен стратегический подход. Необходимо определить, от каких именно изменений и какие именно модули вы хотите закрыть. Это решение следует принимать опираясь на опыт, а также знания предметной области и пользователей системы.

Нарушение принципа открытости-закрытости приводит к ситуациям, когда изменение в одном модуле вынуждает менять другие, связанные с ним. Это в свою очередь нарушает SRP, потому что весь код, который меняется по какой-то одной причине, должен быть собран в одном модуле. (Разные модули — разные причины для изменения.)

На примере

На схеме ниже объект Client непосредственно связан с объектом Server. Если нам вдруг понадобится, чтобы Client мог работать с разными объектами Server, нам придётся поменять его код.

Структура, нарушающая OCP

Чтобы решить эту проблему, необходимо связывать объекты не напрямую, а через абстракции. Если все объекты Server имплементируют интерфейс Abstract Server, то нам уже не придётся менять код объекта Client для замены одного объекта Server на другой.

Абстракция помогает развязать модули

Коротко

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

  • заставляет проектировать модули так, чтобы они делали только одну вещь и делали её хорошо;
  • побуждает связывать сущности через абстракции (а не реализацию) там, где могут поменяться бизнес-требования;
  • обращает внимание проектировщиков на места стыка и взаимодействие сущностей;
  • позволяет сократить количество кода, который необходимо менять при изменении бизнес-требований;
  • делает внесение изменений безопасным и относительно дешёвым.

Материалы к разделу

Вопросы