Глава 8. Принцип открытости/закрытости
Принцип открытости/закрытости (Open-Closed Principle; OCP) был сформулирован Бертраном Мейером в 1988 году. [23] Bertrand Meyer. Object Oriented Software Construction , Prentice Hall, 1988, p. 23 ( Бертран Мейер. Объектно-ориентированное конструирование программных систем. Русская редакция, 2005. — Примеч. пер. ).
Он гласит:
Программные сущности должны быть открыты для расширения и закрыты для изменения.
Иными словами, должна иметься возможность расширять поведение программных сущностей без их изменения.
Это одна из основных причин, почему мы изучаем архитектуру программного обеспечения. Очевидно, если простое расширение требований ведет к значительным изменениям в программном обеспечении, значит, архитекторы этой программной системы потерпели сокрушительное фиаско.
Большинство студентов, изучающих проектирование программного обеспечения, признают принцип OCP как руководство по проектированию классов и модулей. Но на уровне архитектурных компонентов этот принцип приобретает еще большую значимость.
Увидеть это поможет простой мысленный эксперимент.
Представьте, что у нас есть финансовая сводка. Содержимое страницы прокручивается, и отрицательные значения выводятся красным цветом.
Теперь допустим, что заинтересованные лица попросили нас представить ту же информацию в виде отчета, распечатанного на черно-белом принтере. Отчет должен быть разбит на страницы, включать соответствующие верхний и нижний колонтитулы на каждой странице и колонку меток. Отрицательные значения должны заключаться в круглые скобки.
Очевидно, что для этого придется написать новый код. Но как много старого кода придется изменить?
В программном обеспечении с хорошо проработанной архитектурой таких изменений должно быть очень немного. В идеале их вообще не должно быть.
Как? Правильно разделяя сущности, которые изменяются по разным причинам (принцип единственной ответственности), и затем правильно организуя зависимости между этими сущностями (принцип инверсии зависимостей).
Применяя принцип единственной ответственности, можно прийти к потоку данных, изображенному на рис. 8.1. Некоторая процедура анализирует финансовые данные и производит данные для отчета, которые затем форматируются двумя процедурами формирования отчетов.
Рис. 8.1.Результат применения принципа единственной ответственности
Самое важное, что нужно понять, — в данном примере в создание отчета вовлечены две отдельные ответственности: вычисление данных для отчета и представление этих данных в форме веб-отчета или распечатанного отчета.
Сделав такое разделение, мы должны организовать зависимости в исходном коде так, чтобы изменения в одной из ответственностей не вызывали необходимости изменений в другой. Кроме того, новая организация должна гарантировать возможность расширения поведения без отмены изменений.
Этого можно добиться, выделив процессы в классы, а классы в компоненты, ограниченные двойными линиями на рис. 8.2. Компонент в левом верхнем углу на этом рисунке — контроллер . В правом верхнем углу — интерактор , или посредник . В правом нижнем углу — база данных . Наконец, в левом нижнем углу изображены четыре компонента — презентаторы и представления .
Классы, отмеченные символами , — это интерфейсы; отмеченные символами — это структуры данных (data structures). Простые стрелки соответствуют отношениям использования . Стрелки с треугольным наконечником соответствуют отношениям реализации или наследования .
Первое, на что следует обратить внимание, — все зависимости определены на уровне исходного кода . Стрелка, направленная от класса A к классу B, означает, что в исходном коде класса A упоминается имя класса B, но в коде класса B не упоминается имя класса A. Так, на рис. 8.2 диспетчер финансовых данных знает о существовании шлюза через отношение реализации , а шлюз финансовых данных ничего не знает о диспетчере.
Рис. 8.2.Выделение процессов в классы и выделение классов в компоненты
Читать дальше
Конец ознакомительного отрывка
Купить книгу