Форум
Философия программирования
Тема
Как правильно задавать вопросы
B
I
abc
U
X
3
X
3
H1
H2
H3
H4
H5
H6
Asm
C/C++
C#
Erlang
Haskell
IDL
Java
Lisp
MSIL
Nemerle
ObjC
OCaml
Pascal
Perl
PHP
Prolog
Python
Ruby
Rust
SQL
VB
Здравствуйте, Геннадий Васильев, Вы писали: ГВ>Здравствуйте, SV., Вы писали: Z>>>LSP затрагивает не столько публичный интерфейс иерархии классов, сколько внешние методы с ней работающие. Именно они должны работать корректно с любым потомком. Если метод принимает на вход Printer, он должен точно так же корректно работать если ему передали ColorPrinter или MatrixPrinter. SV.>>Ослу понятно, что если конструкторы будут различаться (требовать разных инициализационных данных - connection string / console), то и методы, которые инстанцируют логгеры, тоже будут различаться. SV.>>Вопрос в чистом виде такой: классы, которые дают возможность одинаково себя использовать, но требуют по-разному порождать - удовлетворяют LSP или нет? Я для себя ответил так: It's OK. ГВ>Не совсем правильная постановка вопроса, потому что ты здесь упускаешь из виду, что LSP формулируется относительно некоторого [i]базового[/i] типа, соответственно, классы могут удовлетворять LSP тоже только по отношению к какому-то базовому типу. Поясню на примере. ГВ>[ccode] ГВ>class Shape { ГВ>public: ГВ> virtual void draw() = 0; ГВ> virtual void setCanvas(Canvas *) = 0; ГВ>}; ГВ>class Circle : public Shape { ГВ>public: ГВ> Circle(Point center, int radius); ГВ> void draw(); ГВ> void setCanvas(Canvas *); ГВ>}; ГВ>class Line : public Shape { ГВ>public: ГВ> Line(Point begin, Point end); ГВ> void draw(); ГВ> void setCanvas(Canvas *); ГВ>}; ГВ>[/ccode] ГВ>Предположим для ясности, что реализации draw и setCanvas соответствуют всем соглашениям и т.п. Так вот, базовый тип (Shape) [b]не[/b] содержит определения конструктора, следовательно способ порождения его наследников не должен учитываться при оценке LSP-compliancy. Собственно, наследники могут вводить ещё туеву хучу своих собственных методов по необходимости, но если соглашения Shape при этом не нарушаются, то иерархия остаётся LSP-compliant для базового Shape. ГВ>Конструкторы могут быть включены в оценку LSP-compliancy только в том случае, если язык программирования допускает наследование конструкторов и при использовании требуется определённая сигнатура конструктора. Иначе они всегда будут относиться к одному-единственному типу и вопрос о об LSP-compliant наследовании не стоит. Тут ещё есть такой парадокс, что имя конструктора нередко должно совпадать с именем типа, а значит, в точке использования конструктора почти всегда будет указан конкретный тип и вопрос о наследовании снова отпадает сам собой. Но если языки или технология позволяют выбрать тип по содержимому переменной (GUID, строковое имя, ссылка на метакласс...) и потом вызвать конструктор некоторым унифицированным образом - тут да, конструктор может быть включён в оценку LSP-compliancy. Вот такая вот путаница. :) ГВ>Кстати, если внимательно прочесть твой вопрос: ГВ>[q]классы, которые дают возможность одинаково себя использовать, но требуют по-разному порождать[/q]...то в нём можно найти скрытое противоречие: "одинаково использовать" vs. "по-разному порождать". Из этого противоречия следует, что порождение находится за пределами "использования" и в оценке LSP-compliancy, таким образом, автоматически не участвует. Так что, да, It's OK. Definitely. ГВ>Собственно, вне контекста использования (а базовый тип - это своеобразная квинтэссенция способов использования наследников) рассуждать об LSP-compliancy типов вообще нельзя. Уж коль скоро созданы разные классы, то хоть в чём-то они будут отличаться, а значит почти всегда можно найти такую точку зрения, с которой наследники окажутся нарушающими LSP, другое дело - надо ли её искать. :) SV.>>Пример с логгерами приведен. Другой пример: простенький векторный редактор. Вы щелкаете по кнопке "Рисую прямоугольник". Window [Controller + View] запоминает режим и в соответствии с ним показывает вам рамку после первого щелчка. После отпускания кнопки мыши отрабатывает switch, и в класс Document [Model] уходит команда "Новый прямоугольник". Тот инстанцирует Rect, добавляет его в коллекцию фигур, и только после этого разница между ним и каким-нибудь кругом исчезает. ГВ>Угу, верно. С одним "но". Разница запросто может исчезнуть гораздо раньше, если вместо "режима нового прямоугольника" рисование предварительной фигуры будет возложено на соответствующий класс. То есть рамку рисует Rect, овал изображается классом Ellipse и т.п. Ну а то, как эти классы будут пользоваться мышкой и какие параметры хранить - это уже их личное дело. SV.>>Если есть возражения по сути, welcome. ГВ>Да возражений особо нет, так - уточнения. :)
Теги:
Введите теги разделенные пробелами. Обрамляйте в кавычки словосочетания с пробелами внутри, например:
"Visual Studio" .NET
Имя, пароль:
Загрузить
Нравится наш сайт?
Помогите его развитию!
Отключить смайлики
Получать ответы по e-mail
Проверить правописание
Параметры проверки …