Как часто используется принцип Лискова
Что проверяют
Вопрос с подвохом: принцип не применяют время от времени, он действует каждый раз, когда вы передаёте наследника или реализацию туда, где ожидают базовый тип. Проверяют, видите ли вы его в реальном коде, а не только в примере с птицами. Следом просят показать нарушение в стандартной библиотеке .NET.
Как отвечать
Сформулируйте через контракт: код, работающий с базовым типом, должен правильно работать с любым его подтипом. Отсюда правила для наследника:
- предусловия: не усиливаются. Базовый метод принимает любое число, значит наследник не имеет права отвергать отрицательные;
- постусловия: не ослабляются. Обещал вернуть не
null, значит не возвращает; - инварианты и исключения: наследник не ломает состояние, которое база считает корректным, и не бросает исключений, которых клиент не ждёт.
Примеры из .NET, которые стоит знать:
- массивы:
T[]реализуетIList<T>, ноAddбросаетNotSupportedException. По интерфейсу коллекция подходит, по поведению нет; - ковариантность массивов:
object[] items = new string[1]; items[0] = 1;компилируется и падает сArrayTypeMismatchException; ReadOnlyCollection<T>: тот жеIList<T>с исключениями на запись. Поэтому появилисьIReadOnlyList<T>иIReadOnlyCollection<T>, решение через разделение интерфейсов;Stream: флагиCanRead,CanSeek,CanWriteвшиты в контракт, и клиент обязан их проверять.
Вариантность обобщений (out в IEnumerable<T>, in в IComparer<T>) проверяется компилятором и безопасна, в отличие от массивов. В повседневной работе LSP проявляется в DI: вы подменяете IRepository фейком в тестах или декоратором с кешем, и всё работает, пока реализации держат контракт.
Где спотыкаются
Рассказывают только про квадрат и прямоугольник или про пингвина. Без примера из своего кода или из BCL ответ звучит заученно.
Считают допустимым override, который бросает NotImplementedException. Это прямое нарушение: клиент получит исключение там, где его не ждал.
Не замечают симптом в клиентском коде: проверки вида if (shape is Square) появляются как раз тогда, когда подтип нельзя использовать вместо базового.