Принцип подстановки Лисков (LSP из SOLID)
От: igor-booch Россия  
Дата: 24.07.11 13:54
Оценка: :))) :))) :))
http://en.wikipedia.org/wiki/Liskov_substitution_principle

Насколько я понял принцип гласит, что если в программе заменить базовые классы классами наследниками, то ничего не должно сломаться. По-мойму бред. Или я что-то неправильно понял.
http://rsdn.ru/Info/rules.xml
Re: Принцип подстановки Лисков (LSP из SOLID)
От: LaptevVV Россия  
Дата: 24.07.11 13:56
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>http://en.wikipedia.org/wiki/Liskov_substitution_principle


IB>Насколько я понял принцип гласит, что если в программе заменить базовые классы классами наследниками, то ничего не должно сломаться. По-мойму бред. Или я что-то неправильно понял.

Это динамически происходит. "На место объекта базового класса МОЖНО подставить объект производного класса". Обратно — нельзя.
Будильник — это часы, но не всякие часы — будильник.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: Принцип подстановки Лисков (LSP из SOLID)
От: igor-booch Россия  
Дата: 24.07.11 14:08
Оценка:
LVV>Это динамически происходит.
Что значит динамически?

LVV>"На место объекта базового класса МОЖНО подставить объект производного класса".

По-мойму это справедливо если классы наследники только добавляют новые методы. Если в классах наследниках происходит перекрытие методов базового класса, то такая подстановка сломает программу. Например базовый класс принтер, класс наследник цветной лазерный принтер. Метод печатать.

LVV>Обратно — нельзя.

с этим я абсолютно согласен

LVV>Будильник — это часы, но не всякие часы — будильник.

с этим я тоже абсолютно согласен
http://rsdn.ru/Info/rules.xml
Re[3]: Принцип подстановки Лисков (LSP из SOLID)
От: Ziaw Россия  
Дата: 24.07.11 14:33
Оценка: 1 (1) +2
Здравствуйте, igor-booch, Вы писали:

LVV>>"На место объекта базового класса МОЖНО подставить объект производного класса".

IB>По-мойму это справедливо если классы наследники только добавляют новые методы. Если в классах наследниках происходит перекрытие методов базового класса, то такая подстановка сломает программу. Например базовый класс принтер, класс наследник цветной лазерный принтер. Метод печатать.

Для того принцип и существует, чтобы замена принтера на цветной не ломала программу. Почему она должна сломаться мне совершенно непонятно.
Re[3]: Принцип подстановки Лисков (LSP из SOLID)
От: LaptevVV Россия  
Дата: 24.07.11 14:50
Оценка: +1 -2
Здравствуйте, igor-booch, Вы писали:


LVV>>Это динамически происходит.

IB>Что значит динамически?
То есть во время работ ы программы

LVV>>"На место объекта базового класса МОЖНО подставить объект производного класса".

IB>По-мойму это справедливо если классы наследники только добавляют новые методы. Если в классах наследниках происходит перекрытие методов базового класса, то такая подстановка сломает программу. Например базовый класс принтер, класс наследник цветной лазерный принтер. Метод печатать.
Дык это же ТОЛЬКО принцип.А уж как его использовать — дело программиста. Но обратите внимание, ВСЕ ОО-языки этот принцип поддерживают.
В С++ этот принцип работает для открытого наследования.
Собственно, виртуальность — это оно и есть...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Принцип подстановки Лисков (LSP из SOLID)
От: skeptic  
Дата: 24.07.11 15:49
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>http://en.wikipedia.org/wiki/Liskov_substitution_principle


IB>Насколько я понял принцип гласит, что если в программе заменить базовые классы классами наследниками, то ничего не должно сломаться. По-мойму бред. Или я что-то неправильно понял.


Понял прочитанное ты правильно, да. А вот с выводами почему-то всё сложно.
С какой стати твоя программа должна ломаться из за замены в логгере,например,сущности отвечающей за вывод в stdout на сущность отвечающую за вывод в файл?
Re: Принцип подстановки Лисков (LSP из SOLID)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 24.07.11 19:04
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>http://en.wikipedia.org/wiki/Liskov_substitution_principle


IB>Насколько я понял принцип гласит, что если в программе заменить базовые классы классами наследниками, то ничего не должно сломаться. По-мойму бред. Или я что-то неправильно понял.


Правильно понял, но это справедливо только при условии, что наследование (inheritance) типов в данной программной системе действительно выражает отношение "тип-подтип" в том смысле, который подразумевает LSP. Обычно полагают, что так оно и есть, но в отдельных случаях это правило может нарушаться.

Говоря другими словами, в программе ничего не должно сломаться при замене базовых классов классами-наследниками, если и только если классы спроектированы с учётом LSP.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[3]: Принцип подстановки Лисков (LSP из SOLID)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 24.07.11 19:16
Оценка: +3
Здравствуйте, igor-booch, Вы писали:

LVV>>"На место объекта базового класса МОЖНО подставить объект производного класса".

IB>По-мойму это справедливо если классы наследники только добавляют новые методы. Если в классах наследниках происходит перекрытие методов базового класса, то такая подстановка сломает программу. Например базовый класс принтер, класс наследник цветной лазерный принтер. Метод печатать.

Угу-угу, это как раз и есть источник сложностей ОО-проектирования. Вот и спроектируй программу так, чтобы замена класса MatrixPrinter на ColorPrinter проходила незаметно для использующего кода.

Собственно, LSP не случайно сформулирован, как "свойство q(x)...". Суть в том, что набор соглашений, справедливых для базового типа должен соблюдаться и для типа-наследника (если они LSP-compliant). Говорим мы при этом об интерфейсных методах, или, скажем, о побочных эффектах в виде генерации какого-то события с заданной периодичностью — не суть важно.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[4]: Принцип подстановки Лисков (LSP из SOLID)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 24.07.11 19:19
Оценка: 1 (1) +1
Здравствуйте, LaptevVV, Вы писали:

LVV>Дык это же ТОЛЬКО принцип.А уж как его использовать — дело программиста. Но обратите внимание, ВСЕ ОО-языки этот принцип поддерживают.

LVV>В С++ этот принцип работает для открытого наследования.
LVV>Собственно, виртуальность — это оно и есть...

Точнее — на C++ можно реализовать LSP с помощью открытого наследования и виртуальных методов.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[2]: Принцип подстановки Лисков (LSP из SOLID)
От: igor-booch Россия  
Дата: 24.07.11 19:50
Оценка: :)
Предположим у нас есть класс SimpleLogger, у него виртуальный метод Log(string message), который просто выводит сообщения на консоль.
Есть класс DbLogger, который наследуется от SimpleLogger. В DbLogger перекрыт метод Log(string message) и добавлена функциональность логирования сообщения в БД.
Теперь меняем в программе SimpleLogger на DbLogger, опаньки, а баз данных то нет, комп от сети отключен, даже connection string нигде не указан. Логирование не работает.
http://rsdn.ru/Info/rules.xml
Re[3]: Принцип подстановки Лисков (LSP из SOLID)
От: skeptic  
Дата: 24.07.11 20:27
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>Предположим у нас есть класс SimpleLogger, у него виртуальный метод Log(string message), который просто выводит сообщения на консоль.

IB>Есть класс DbLogger, который наследуется от SimpleLogger. В DbLogger перекрыт метод Log(string message) и добавлена функциональность логирования сообщения в БД.
IB>Теперь меняем в программе SimpleLogger на DbLogger, опаньки, а баз данных то нет, комп от сети отключен, даже connection string нигде не указан. Логирование не работает.


Теперь только объясни себе какой смысл имеет логгирование в базу там где этой базы нет? Может если базы нет то объект который в неё захочет писать должен так и сказать мол базы насяйника нет, а не крушить всю систему из за этого? Ну а кто то вышестоящий увидев такую пьянку может попытаться заменить этот ваш DbLogger на что то более подходящее, что гораздо проще будет если иерархия построена на LSP. И это нормальное поведение, где вы тут нарушение LSP увидели я не понимаю.
LSP относится к дизайну системы, он как бы говорит нам — "Поразмысли над тем что бы спроектировать систему вот так и вероятно в последствии не будет так мучительно больно за бесцельно потраченные человеко-часы саппорта."
Re[3]: Принцип подстановки Лисков (LSP из SOLID)
От: hardcase Пират http://nemerle.org
Дата: 24.07.11 20:43
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>Предположим у нас есть класс SimpleLogger, у него виртуальный метод Log(string message), который просто выводит сообщения на консоль.

IB>Есть класс DbLogger, который наследуется от SimpleLogger. В DbLogger перекрыт метод Log(string message) и добавлена функциональность логирования сообщения в БД.

А почему DbLogger должен быть наследником SimpleLogger?
/* иЗвиНите зА неРовнЫй поЧерК */
Re[3]: Принцип подстановки Лисков (LSP из SOLID)
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 24.07.11 20:48
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>Предположим у нас есть класс SimpleLogger, у него виртуальный метод Log(string message), который просто выводит сообщения на консоль.

IB>Есть класс DbLogger, который наследуется от SimpleLogger. В DbLogger перекрыт метод Log(string message) и добавлена функциональность логирования сообщения в БД.
IB>Теперь меняем в программе SimpleLogger на DbLogger, опаньки, а баз данных то нет, комп от сети отключен, даже connection string нигде не указан. Логирование не работает.

Это означает, что отношение типов SimpleLogger-DbLogger не является отношением "тип-подтип" в том смысле, который подразумевает LSP. По идее, для полного LSP-compliancy где-то отдельно должны упаковываться "настроечные параметры", специфичные для каждого класса.

Ну или как вариант, придётся сократить область соблюдения LSP только до интерфейса собственно логгирования (метода Log(string) ), а остальные параметры классов будут использоваться отдельно, вне контекста, в котором должен соблюдаться LSP. Простейший пример такого компромисса — "фабричный метод", когда специфика конструкторов разных классов упоминается только внутри самого фабричного метода, а остальные потребители работают с созданными экземплярами одинаково. Отсюда, как ты понимаешь, мы приходим к концепции "интерфейса" (interface), как к явному декларированию набора свойств, которые должны быть реализованы всеми классами, реализующими соответствующий интерфейс (сравни с формулировкой LSP).
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re: Принцип подстановки Лисков (LSP из SOLID)
От: z00n  
Дата: 25.07.11 03:53
Оценка: 2 (1)
Здравствуйте, igor-booch, Вы писали:

IB>http://en.wikipedia.org/wiki/Liskov_substitution_principle


IB>Насколько я понял принцип гласит, что если в программе заменить базовые классы классами наследниками, то ничего не должно сломаться. По-мойму бред. Или я что-то неправильно понял.


Это еще что — попробуйте поразмыслить об контравариантности аргументов функций
http://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)

A call to a function with a parameter of type T (defined as fun f (x : T) : Integer) can be replaced by a call to a function g (defined as fun g (x : S) : Integer) if T ≤ S. In other words, if g cares less about the type of its parameter, then it can replace f anywhere, since both return an Integer. So, in a language accepting function arguments, g ≤ f and the type of the parameter to f is said to be contravariant.

Re[3]: Принцип подстановки Лисков (LSP из SOLID)
От: minorlogic Украина  
Дата: 25.07.11 06:07
Оценка: +3 -1
Здравствуйте, igor-booch, Вы писали:

IB>Предположим у нас есть класс SimpleLogger, у него виртуальный метод Log(string message), который просто выводит сообщения на консоль.

IB>Есть класс DbLogger, который наследуется от SimpleLogger. В DbLogger перекрыт метод Log(string message) и добавлена функциональность логирования сообщения в БД.
IB>Теперь меняем в программе SimpleLogger на DbLogger, опаньки, а баз данных то нет, комп от сети отключен, даже connection string нигде не указан. Логирование не работает.

Кривой пример. Для консольного логера тоже могут быть проблемы , нет консоли , нет райнайм библиотеки, не хватает памяти для логирования и т.п.
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[5]: Принцип подстановки Лисков (LSP из SOLID)
От: jazzer Россия Skype: enerjazzer
Дата: 25.07.11 06:50
Оценка: +2 :)
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Здравствуйте, LaptevVV, Вы писали:


LVV>>Дык это же ТОЛЬКО принцип.А уж как его использовать — дело программиста. Но обратите внимание, ВСЕ ОО-языки этот принцип поддерживают.

LVV>>В С++ этот принцип работает для открытого наследования.
LVV>>Собственно, виртуальность — это оно и есть...

ГВ>Точнее — на C++ можно реализовать LSP с помощью открытого наследования и виртуальных методов.


А также шаблонов
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Принцип подстановки Лисков (LSP из SOLID)
От: MasterZiv СССР  
Дата: 25.07.11 06:51
Оценка:
On 24.07.2011 17:54, igor-booch wrote:

> Насколько я понял принцип гласит, что если в программе заменить базовые классы

> классами наследниками, то ничего не должно сломаться. По-мойму бред. Или я
> что-то неправильно понял.

Ты неправильно понял.
Posted via RSDN NNTP Server 2.1 beta
Re[3]: Принцип подстановки Лисков (LSP из SOLID)
От: jazzer Россия Skype: enerjazzer
Дата: 25.07.11 06:52
Оценка:
Здравствуйте, igor-booch, Вы писали:

IB>Предположим у нас есть класс SimpleLogger, у него виртуальный метод Log(string message), который просто выводит сообщения на консоль.

IB>Есть класс DbLogger, который наследуется от SimpleLogger. В DbLogger перекрыт метод Log(string message) и добавлена функциональность логирования сообщения в БД.
IB>Теперь меняем в программе SimpleLogger на DbLogger, опаньки, а баз данных то нет, комп от сети отключен, даже connection string нигде не указан. Логирование не работает.

Это всего лишь значит, что у тебя LSP не соблюдается — ССЗБ
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[3]: Принцип подстановки Лисков (LSP из SOLID)
От: MasterZiv СССР  
Дата: 25.07.11 07:01
Оценка: +1
On 24.07.2011 18:08, igor-booch wrote:

> LVV>"На место объекта базового класса МОЖНО подставить объект производного класса".

> По-мойму это справедливо если классы наследники только добавляют новые методы.
> Если в классах наследниках происходит перекрытие методов базового класса, то
> такая подстановка сломает программу. Например базовый класс *принтер*, класс
> наследник*цветной лазерный принтер*. Метод *печатать*.

Это -- принцип "как оно должно быть", а не принцип "как оно есть на самом деле
в неработающих программах".

Открытое наследование в ООП (в большинстве языков программирования)
позволяет тебе использовать принцип подстановки. Т.е. подставить
вместо объекта базового класса объект-наследник. Наличие этого
принципа даёт тебе гарантию, что программа твоя соберётся
(скомпилируется, загрузится и т.п.), т.е. язык программирования
тебе ДАСТ ЭТО СДЕЛАТЬ. Но что это будет работать естественно
никто не гарантирует. Это ДОЛЖНО работать в хорошо спроектированной
и закодированной программе, иначе в ООП просто нет никакого смысла.

Кстати, есть разные языки относительно соблюдения этого
принципа. Есть "статические" языки, где проверка типа происходит
на этапе компиляции программы (сборки). Там этот принцип
соблюдается относительно всего класса (предка и наследника)
целиком. Есть "динамические" языки, где на этапе сборки
программы конкретный тип не проверяется, а проверка эта
делается только во время работы на этапе посылки объекту
какого-то класса определённого сообщения (вызова метода то есть).
В таких языках класс-"наследник" даже может быть формально
не унаследованным от своего класса-"предка", и там уже речь
идёт о "соблюдении протоколов".
Posted via RSDN NNTP Server 2.1 beta
Re: Принцип подстановки Лисков (LSP из SOLID)
От: jazzer Россия Skype: enerjazzer
Дата: 25.07.11 07:35
Оценка: 37 (2) +2
Здравствуйте, igor-booch, Вы писали:

IB>http://en.wikipedia.org/wiki/Liskov_substitution_principle


IB>Насколько я понял принцип гласит, что если в программе заменить базовые классы классами наследниками, то ничего не должно сломаться. По-мойму бред. Или я что-то неправильно понял.


Это признак корректности спроектированной системы типов и отношений между ними. Если он не соблюдается — ССЗБ.
Он должен соблюдаться, иначе ты получаешь кривую программу.

Фактически, это даже не принцип в том смысле, что "так бы делать хорошо".
LSP является определением отношения тип-подтип.

Другое дело — когда у тебя есть какие-то конструкции в языке, которые позволяют номинально это отношение выразить, даже если формально оно нарушено.
Тогда ты можешь выразить отношение тип-подтип, просто использовав сооответствующую синтаксическую конструкцию для выражения наследования в твоем языке (class Derived: public Base), но это не сделает их настоящей парой тип-подтип, пока ты не приложишь специальные усилия, чтобы удовлетворить LSP.

Причем, обрати внимание, LSP сформулирован с терминах свойств типов, а это может быть все, что угодно — от сигнатуры метода до времени времени его работы.
Т.е. свойство "можно позвать метод с таким-то именем и с такими параметрами" само по себе обычно бессмысленно, потому что тебе нужно чтоб не просто позвать, тебе нужно конкретное поведение, но это единственное, что могут проверить компиляторы автоматически. А неопытные программисты думают, что если проверки компилятора прошли — они уже все реализовали наследование правильно.
Реальное свойство, например, может быть выражено так: "У метода есть некоторые предусловия, и если они не нарушены, то будут соблюдаться некоторые постусловия" — проверка этого лежит целиком на программисте, проектирующем и реализующем производный класс.

Естественно, никто не запретит тебе какой-то принцип нарушить, но вот только ты уже себе сам будешь ЗБ, когда твоя программа начнет падать, вести себя странно, или просто с большим трудом поддаваться поддержке и изменениям, провоцируя ошибки на каждом шагу.
Каждая пара классов, нарушающая LSP — это подводные грабли.
Это же относится и к остальным принципам SOLID.
К примеру — никто не запрещает тебе нарушить Single responsibility principle и написать универсальный всемогутер — только, я думаю, ты сам знаешь, каким геморроем оборачивается поддержка такого монстра.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.