Что такое принцип подстановки Барбары Лисков
Что проверяют
Понимаете ли вы LSP как правило о контрактах, а не как «у наследника те же методы». Следом обычно просят пример нарушения из своего кода и спрашивают, как его чинить: композицией, разделением интерфейсов или sealed-иерархией.
Как отвечать
Формулировка Лисков и Уинг: если код корректно работает с базовым типом, он так же корректно работает с любым его подтипом, не зная, какой именно получил. Совпадение сигнатур здесь не главное, его проверит компилятор. Главное это поведение:
- предусловия: подтип не может требовать от вызывающего больше, чем базовый тип;
- постусловия: подтип не может обещать меньше;
- инварианты: то, что всегда верно для базового типа, остаётся верным и для подтипа;
- исключения: подтип не бросает новых исключений там, где контракт их не предусматривал.
Классика: Square наследует Rectangle, и код, который задаёт ширину 5 и высоту 4 и ждёт площадь 20, получает 16.
Пример ближе к Android: интерфейс UserRepository с методом suspend fun getUser(id: String): User. Реализация CachedUserRepository при промахе кэша бросает IllegalStateException вместо похода в сеть. Типы совпадают, но ViewModel, написанная под контракт «вернёт пользователя или сетевую ошибку», падает.
Лечение: не наследоваться ради переиспользования кода, выносить разные возможности в разные интерфейсы (Flyable отдельно от Bird), закрытые варианты держать в sealed interface, где when проверяется компилятором на полноту. Kotlin помогает и тем, что классы по умолчанию final: наследование нужно разрешить явно через open.
Где спотыкаются
Отвечают «подкласс можно подставить вместо родителя» и останавливаются. Это пересказ названия, без пред- и постусловий не видно, что вы понимаете, что именно ломается.
Лечат нарушение через if (bird is Penguin) в клиентском коде. Проверка типа в месте использования как раз и есть симптом нарушенного LSP.
Считают, что принцип только про наследование классов. Он в той же мере касается реализаций интерфейсов и фейков в тестах: фейковый репозиторий с другим поведением делает тест ложно зелёным.