Что такое принцип открытости-закрытости (Open-Closed Principle)
Что проверяют
Понимаете ли вы формулировку и знаете ли, что принцип не требует применять его везде.
Как отвечать
Формулировка: модуль должен быть открыт для расширения и закрыт для изменения. Новое поведение добавляется без правки существующего кода.
Смысл в снижении риска: изменение работающего кода может сломать то, что уже проверено, а добавление нового кода такого риска не несёт.
Типичный признак нарушения это ветвление по типу, которое приходится дополнять при каждом новом варианте:
double fee(Payment p) {
if (p.type == CARD) return p.amount * 0.02;
if (p.type == SBP) return 0;
// новый способ оплаты означает правку этого метода
}Каждый новый способ требует изменить существующий метод, перетестировать его и рискнуть сломать прежние ветки.
Решение через полиморфизм: интерфейс расчёта комиссии и по реализации на способ оплаты. Новый способ это новый класс, и ни одна строка старого кода не меняется. В контейнере зависимостей реализации подхватываются автоматически.
Способы достижения помимо полиморфизма: стратегия, передаваемая параметром, точки расширения через обратные вызовы, конфигурация вместо ветвлений.
Обязательная оговорка, без которой ответ превращается в догму: не нужно делать точки расширения везде заранее. Попытка предусмотреть все будущие изменения даёт архитектуру из абстракций с одной реализацией, которую тяжело читать, а угадать направление изменений всё равно не получается. Правильный ход: писать просто, а расширяемость вводить в тот момент, когда второй вариант действительно появился. Тогда вы знаете, по какой оси нужна гибкость.
Ещё одна честная оговорка: ветвление на два случая, которые не меняются годами, переписывать в иерархию классов вредно. Принцип про места, где изменения ожидаются.
Где спотыкаются
Пересказывают формулировку без примера.
Заводят интерфейс на каждый класс на всякий случай.
Не замечают нарушения в разросшемся ветвлении по типу.
Считают, что принцип запрещает править код вообще.