SOLID.LSP + ООП.Полиморфизм = противоречиe?

После изучения разных источников о Liskov Substitutioin Principle , так и не нашел ответа на вопрос:
Как LSP сочетается с полиморфизмом в ООП?
Ведь судя по определению, LSP предписывает наследникам сохранять поведение (контракт) базового класса.
Тогда как полиморфизм - это способность изменять поведение методов базового класса в наследниках. Если трактовать LSP буквально, то я вижу в этих подходах однозначное противоречие.
Собственно, как его разрешить?
  • Вопрос задан
  • 622 просмотра
Пригласить эксперта
Ответы на вопрос 3
@Mercury13
Программист на «си с крестами» и не только
LSP предписывает наследникам сохранять поведение (контракт) базового класса.

Не поведение, а ограничения. LSP разрешает только усиливать требования к себе, и только ослаблять — требования к другим. Поведение же может меняться как хочешь в рамках этих ограничений.

Например, интерфейс Stream позволяет мультиплексированные потоки (то есть потоки, где мы не можем считать записанное, чтение и запись идёт по разным каналам и никак не связаны друг с другом — например, COM-порты), а какой-нибудь BufferedStream ограничивается только потоками, где мы пишем в какую-нибудь цепочку байтов (например, файл), и читаем из неё же, без мультиплексирования.
Ответ написан
makarychev13
@makarychev13
Тогда как полиморфизм - это способность изменять поведение методов базового класса в наследниках

Довольно странное утверждение. Полиморфизм - это скорее способность взаимозаменяемости типов. То есть в метод можно передать и класс А, и класс В : А.

Принцип LSP же как раз о том, как лучше этого достигнуть
Ответ написан
Появилось требование - изменить формат некоторых отчетов на CSV.

А кто сказал, что может появиться такое требование? Вернее, что вы сможете его удовлетворить без изменения контракта?

Ведь у вас какой контракт? Что метод MakeReport возвращает html-отчёт? Так как же вы вообще сможете реализовать возврат CSV, не поменяв контракт?

А вот если вы таки поменяете контракт, например скажете что "MakeReport возвращает поток (текстовый или двоичный) конечного размера", то тогда генерация и возврат CSV вполне себе лягут в такой контракт. Конечно, такой контракт уже будет куда более общим - даже тестировать в нём будет особого нечего (кроме того что отчёт вообще сгенерировался и имеет ненулевую длину).

С другой стороны, кто вам мешает написать тесты на конкретные реализации этого контракта? Ведь юнит-тестирование на то и модульное, что может знать больше конкретики об отдельном взятом модуле.

Всё просто, не так ли?

Принцип подстановки говорит - я поставлю рамки, ограничения (т.е. контракт), и все экземпляры подклассов должны ему удовлетворять. Полиморфизм говорит - отлично, значит у нас возможность определить СПЕЦИФИЧНОЕ поведение, которое может отличаться от других специфичных поведений, но при этом все они будут делать что-то вполне ожидаемое и ЗАРАНЕЕ ОГОВОРЕННОЕ.

Сам факт того, что вы составляете СОГЛАШЕНИЯ, выполнения которых ожидают клиенты класса, даёт вам право ВО ВСЕХ ОСТАЛЬНЫХ аспектах вести себя КАК ВАМ ВЗДУМАЕТСЯ (ну я немного преувеличил, но суть такова) в каждом из подклассов.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы