Принцип открытости/закрытости
Принцип открытости/закрытости (Open‐Closed Principle) впервые был сформулирован Бернардом Мейером в 1988 году. Роберт К. Мартин говорил о нем так «Наиболее важный принцип открытости/закрытости гласит «Сущности программы (классы, модули, функции и т.п.) должны быть открыты для расширения, но закрыты для изменений». Следование этому принципу гарантирует, что класс определен достаточно, чтобы делать то, что он должен делать. Добавление любых дополнительных функций может быть реализовано путем создания новых сущностей, которые расширяют возможности существующего класса и добавляют дополнительные функции самим себе. Таким образом можно предотвратить частые и тривиальные изменения в хорошо зарекомендовавшем себя классе низкого уровня. Допустим, у нас есть приложение для магазина одежды. Среди функций системы есть функция применения специальных скидок в зависимости от типа одежды. Пример ниже показывает один из способов реализации этого требования. В примере у нас есть класс DiscountCalculator, который умеет хранить тип одежды. В нем есть функция, которая рассчитывает скидку в зависимости от типа одежды и возвращает новую стоимость за вычетом суммы скидки.
Эта конструкция нарушает принцип открытости/закрытости, поскольку этот класс потребует изменения, если будет добавляться какой-то тип одежды или если сумма скидки на какую-либо одежду изменится.
Как видно из примера выше, теперь у нас есть очень простой базовый класс DiscountCalculator с одним абстрактным методом get_discounted_price. Мы создали новые классы для одежды, которые расширяют базовый класс DiscountCalculator. Следовательно, теперь каждый подкласс будет реализовывать функционал скидок самостоятельно. Сделав так, мы устранили предыдущие ограничения, которые требовали внесения изменений в базовый класс. Теперь, не изменяя базовый класс, мы можем добавлять больше одежды, а также изменять размер скидки на отдельный вид одежды по мере необходимости.
Задачи
Задача 1. Расчёт площади фигур
Дан класс AreaCalculator, который считает площадь разных фигур через if/elif. Нарушает ли он OCP? Добавьте поддержку треугольника, не изменяя существующий код.
Задача 2. Экспорт данных
Класс DataExporter экспортирует данные в разные форматы (JSON, CSV) через условные операторы. Перепроектируйте так, чтобы добавление нового формата (например, XML) не требовало изменения DataExporter.
Задача 3. Уведомления
Класс NotificationService отправляет уведомления по email или SMS в зависимости от параметра. Перепроектируйте с учётом OCP, чтобы можно было добавить push-уведомления без изменения NotificationService.
|
|
Задача 4. Сортировка коллекции
Класс Sorter сортирует массив разными алгоритмами, выбираемыми через строковый параметр. Перепроектируйте так, чтобы новый алгоритм добавлялся без изменения класса Sorter.
Задача 5. Обработка платежей
Класс PaymentProcessor обрабатывает платежи через разные системы (карта, криптовалюта) с помощью условных операторов. Добавьте поддержку оплаты через СБП, не изменяя PaymentProcessor.