Приведи пример нарушения принципа подстановки Лисков
Что проверяют
Понимаете ли вы, что наследование это обещание поведения, а не способ переиспользовать код. По ответу видно, разбирались ли вы с контрактами или помните только историю про страуса.
Как отвечать
Принцип подстановки: код, написанный для базового типа, должен корректно работать с любым наследником, ничего о нём не зная. Наследнику можно ослаблять требования ко входу и усиливать гарантии по результату, но не наоборот, и нельзя бросать исключения, которых базовый контракт не обещал.
Самый честный пример нарушения живёт в стандартной библиотеке: Arrays.asList и неизменяемые обёртки над коллекциями по типу остаются List, но на add бросают UnsupportedOperationException. Метод, принявший List и добавивший элемент, ломается на конкретной реализации.
В Android свои примеры:
- наследник
ViewGroup, у которогоaddViewигнорируется или падает, потому что «детей добавляю только я». Любая разметка с вложенными элементами перестаёт инфлейтиться; - фрагмент, который работает только после своего фабричного метода и падает без аргументов. Система пересоздаёт фрагменты сама после смерти процесса, так что контракт нарушен;
- адаптер списка, который в
onBindViewHolderприводитViewHolderк одному типу без проверки.
Лечение называйте сразу: выделить узкий интерфейс для необязательной способности, предпочесть композицию наследованию, прогонять наследника тестами базового типа.
Где спотыкаются
Останавливаются на птицах и страусах. Пример учебный и знаком всем, интервьюер ждёт случай из кода, который кандидат писал сам.
Считают нарушением любое расширение. Добавить наследнику новый метод можно, нарушение начинается там, где сузили допустимые входы, ослабили гарантии или добавили исключение, которого базовый тип не обещал.
Чинят проверкой типа в вызывающем коде. Условие на конкретный класс выносит поломку наружу и требует правки при каждом новом наследнике, то есть вместо одного принципа ломаются два.