В чем суть принципа Open-Closed и как он относится к изменению контрактов
Что проверяют
Понимаете ли вы OCP не как лозунг «не трогай старый код», а как способ добавлять поведение, не ломая тех, кто уже зависит от вашего API. Вторая половина вопроса про контракты: что именно в интерфейсе нельзя менять безнаказанно и как его всё-таки развивают.
Как отвечать
Принцип сформулировал Бертран Мейер: модуль открыт для расширения и закрыт для изменения. Роберт Мартин переосмыслил его через абстракции: код зависит от интерфейса, новое поведение приходит новой реализацией. Классика: интерфейс PaymentMethod, и новая оплата добавляется классом и регистрацией бина в Spring, без правки switch в сервисе.
Контракт это не только сигнатура:
- сигнатура: имя, параметры, возвращаемый тип, проверяемые исключения;
- семантика: предусловия, постусловия, инварианты. Метод, который возвращал пустой список, а теперь
null, ломает контракт при той же сигнатуре; - принцип подстановки Лисков: реализация не может усиливать предусловия и ослаблять постусловия, иначе расширение через подкласс перестаёт быть безопасным.
Как развивать контракт: новый метод объявлять default (с Java 8), чтобы существующие реализации продолжили компилироваться; старый помечать @Deprecated(forRemoval = true) и убирать в мажорной версии; при несовместимой смене заводить новый интерфейс или версию API рядом со старой.
Сильный ход: назвать обратную сторону. sealed-интерфейсы и switch с сопоставлением по образцу (Java 21) сознательно закрывают иерархию: новый тип ломает все switch, зато компилятор проверяет полноту разбора. Это осознанный выбор, а не нарушение OCP.
Где спотыкаются
Понимают принцип буквально: существующий код нельзя менять никогда. Чинить баги и рефакторить можно, закрыт публичный контракт для внешних клиентов.
Заводят интерфейс на каждый класс «на будущее». Точки расширения нужны там, где изменение уже случалось или явно ожидается, остальное лишняя косвенность.
Считают безопасным добавить в интерфейс абстрактный метод. Все реализации, включая чужие, перестанут компилироваться.