Здравствуйте, Курилка, Вы писали:
К>Кстати — какие тут нарушения ты видишь?
По сути одно... В контракте квадрата будет "лишняя" функциональность унаследованная от прямоугольника (работа со вторым размером).
Далее, зависит от той реализации которая будет выбрана для поддержки этой функциональности. Но в любом случае агрегат не сможет работать с квадратом как прямоугольником.
G><Код поскипан>
G>Реализация R.get_Size может быть различной.... такой какой нам нужно будет — вплоть до вызова R.set_Size(base.Size) перед ретурном. Не суть...
А теперь ответь — как будет работать код, если ты ему передаёшь прямоугольник в указателе на квадрат? Скажем, для вычисления площади? Или, скажем, не площадь нужна, а равномерное распределение фигур по экрану?
Имхо нехилые грабли
Ну не соблюдается LSP ни разу!
Здравствуйте, Курилка, Вы писали:
G>>Реализация R.get_Size может быть различной.... такой какой нам нужно будет — вплоть до вызова R.set_Size(base.Size) перед ретурном. Не суть...
К>А теперь ответь — как будет работать код, если ты ему передаёшь прямоугольник в указателе на квадрат? Скажем, для вычисления площади? Или, скажем, не площадь нужна, а равномерное распределение фигур по экрану? К>Имхо нехилые грабли К>Ну не соблюдается LSP ни разу!
LSP требует лишь чтобы агрегат мог работать с потомками агригируемого класса. Сие означает, что наследуемое поведение должно соблюдаться потомками. И именно в варианте S<-R (и, что странно, этот вариант тут (The Liskov Substitution Principle) не рассмотрен ) это можно "вылечить" реализацией. Если агрегат работает (хочет работать) с R как с S, то R для этого агрегата станет S'ом. Он это сможет сделать. В варианте R<-S — S, как не "выкручивай" реализацию, LSP нарушит.
Суть не в этом... Я точно уверен, что рассматриваемая задача не имеет к LSP никакого отношения. Т.к. ставится и разрешается ещё на уровне этапа анализа предметной области — когда у нас ещё нет ни классов, ни, уж тем более, сигнатур методов и т.п.
Здравствуйте, cranky, Вы писали:
M>>А если рассмотреть целые и действительный числа — что из них родитель, а что предок?
C>Думается, что у них просто общий абстрактный предок (или интерфейс), определяющий общие операции.
Почитайте UML Nontation Guide:
*есть отношение обобщение — отношение частного и общего (is a)
*есть наследование — передача признаков от одного к другому
Так как любое целое является действительным, то действительное предок целого.
Здравствуйте, gbear, Вы писали:
G>Вопрос: Кто из них родитель, а кто предок? Почему?[/i]
G>Я всегда считал, что в свое время "подсмотрел" её у Буча... Но вот что-то сегодня полистал его — ничего похожего не нашёл. Но, блин, вряд ли я её сам придумал
Здравствуйте, gbear, Вы писали:
G>По сути одно... В контракте квадрата будет "лишняя" функциональность унаследованная от прямоугольника (работа со вторым размером).
G>Далее, зависит от той реализации которая будет выбрана для поддержки этой функциональности. Но в любом случае агрегат не сможет работать с квадратом как прямоугольником.
Классический косяк, вызванный тем, что обычно наследование вызывает и наследование интерфейсов, и наследование реализаций. А в данном конкретном случае как не выбери — либо интерфейсы наследуются криво, либо реализации. ИМХО правильным решением этой задачи было бы наследование интерфейсов без наследования реализаций. Примерно так:
public interface IRectangle
{
int Width
{get;}
int Height
{get;}
}
public class Rectangle : IRectangle
{
private int _width;
private int _height;
public int Width
{
get { return _width; }
}
public int Height
{
get { return _height; }
}
}
public class Square : IRectangle
{
private int _size;
public int Size
{
get { return _size; }
}
int IRectangle.Width
{
get { return Size; }
}
int IRectangle.Height
{
get { return Size; }
}
}
Итого: имеем оптимальные публичные интерфейсы в каждом случае и возможность обработки полиморфно.
ANS>>Это именно то. То есть правильный ответ, пожалуй, не Мартин, а Лискова.
E>По-моему, фамилия Лисков не склоняется. По крайней мере везде в русскоязычной литературе было написано "принцип Лисков (Барбара Лисков)", а не "принцип Лисковой"
Иностранные женские фамилии не склоняются (вроде, есть некоторое количество исключений, но их слишком мало). Поэтому, если Лисков — это Барбара, то будет:
И. Барбара Лисков
Р. Барбары Лисков
Д. Барбаре Лисков
В. Барбару Лисков
Т. Барбарой Лисков
П. О Барбаре Лисков
Здравствуйте, Mamut, Вы писали:
M>Иностранные женские фамилии не склоняются (вроде, есть некоторое количество исключений, но их слишком мало). Поэтому, если Лисков — это Барбара, то будет:
A> public interface IRectangle
A> {
A> int Width
A> {get;}
A> int Height
A> {get;}
A> }
A> public class Rectangle : IRectangle <...>
A> public class Square : IRectangle
A> {
A> private int _size;
A> public int Size
A> {
A> get { return _size; }
A> }
A> int IRectangle.Width
A> {
A> get { return Size; }
A> }
A> int IRectangle.Height
A> {
A> get { return Size; }
A> }
A> }
A>
A> Итого: имеем оптимальные публичные интерфейсы в каждом случае и A> возможность обработки полиморфно.
А теперь давай добавим в IRectangle модификацию...
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
AndrewVK,
ПК>> А теперь давай добавим в IRectangle модификацию...
A> И в чем проблема?
В том, что в случае модификации высоты квадрата через интерфейс
IRectangle будет также изменяться и ширина, и наоборот. Если же
квадрат не будет менять высоту синхронно с шириной, он перестанет
быть квадратом. Нарушение инвариантов класса.
В случае передачи в эту функцию квадрата, ее постусловия будут
нарушены. Т.е. функция не будет корректно работать с квадратами.
Нарушение критерия Барбары Лисков.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>В том, что в случае модификации высоты квадрата через интерфейс ПК>IRectangle будет также изменяться и ширина, и наоборот. Если же ПК>квадрат не будет менять высоту синхронно с шириной, он перестанет ПК>быть квадратом. Нарушение инвариантов класса.
Нет, это недостаточная конкретизированность исходной задачи. Тут надо определиться — либо квадрат всего лишь одно из состояний прямоугольника, тогда создание отдельного класса для квадрата бессмысленно, достаточно отдельной функции IsSquare, либо квадрат это особый класс фигуры. Но тогда надо определиться с семантикой операции изменения одного из измерений квадрата. К примеру, если речь идет о некоем векторном редакторе, у которого есть панелька с шириной и высотой, то изменение другого измерения совместно с первым вполне нормальное и ожидаемое поведение. Если в том же редакторе мы хотим разнообразить поведение, для прямоугольника показать два измерения, а для квадрата одно, то задачка решается введением метаданых, привязанных к фигуре и отдельным интерфейсом на чтение и модификацию. В таком раскладе IRectangle по прежнему остается только для чтения, что позволяет работать полиморфным алгоритмам рассчета площади, к примеру, а вот модификация осуществляется другими интерфейсами, например ISingleDimensionShape и IDoubleDimensionShape.
Могут быть и другие решения. Все зависит от задачи.
ПК>Давай представим простой код: ПК>
ПК>В случае передачи в эту функцию квадрата, ее постусловия будут ПК>нарушены. Т.е. функция не будет корректно работать с квадратами. ПК>Нарушение критерия Барбары Лисков.
Нет. Это значит что критерии, использованные для проектирования интерфейсов иные, нежели критерии для проектирования того куска кода, что ты привел. В нем assert написаны исходя из предположения, что Width это просто поле. Но, поскольку на самом деле это не поле, то, в общем случае, делать предположений о тривиальной логике модификаций измерений мы не имеем права, если это специально не оговорено в документации.
Здравствуйте, AndrewVK, Вы писали:
AVK>Нет, это недостаточная конкретизированность исходной задачи. Тут надо определиться — либо квадрат всего лишь одно из состояний прямоугольника, тогда создание отдельного класса для квадрата бессмысленно, достаточно отдельной функции IsSquare, либо квадрат это особый
Как по мне, то это самое правильное решение. Плюс добавить метод который позволяет одновременно установить ширину и высоту в одно и тоже значение. Тогда программист должен явно выбрать, что он хочет сделать.
Кстати, этой проблемы с нарушением инвариантов не будет если не будет мутирующих методов.
Здравствуйте, mibe, Вы писали:
M>Почитайте UML Nontation Guide: M> *есть отношение обобщение — отношение частного и общего (is a) M> *есть наследование — передача признаков от одного к другому
Здравствуйте, Andrei N.Sobchuck, Вы писали:
AVK>>Нет, это недостаточная конкретизированность исходной задачи. Тут надо определиться — либо квадрат всего лишь одно из состояний прямоугольника, тогда создание отдельного класса для квадрата бессмысленно, достаточно отдельной функции IsSquare, либо квадрат это особый
ANS>Как по мне, то это самое правильное решение.
Нельзя делать столь определенный вывод, не зная исходных условий.
Здравствуйте, mihoshi, Вы писали:
M>Здравствуйте, cranky, Вы писали:
LK>>>Считаю, что правильный ответ: родитель — квадрат.
C>>скорее прямоугольник, у него ширина и высота, а квадрат — это уже его специализация, где w==h
M>А если рассмотреть целые и действительный числа — что из них родитель, а что предок?
Мне больше нравится другой пример, в нем соблазнов больше.
Комплексные и действительные числа, у которых кроме арифметики определена модифицирующая операция (метод) взятия квадратного корня TakeSqrt().
Здравствуйте, LtrK2, Вы писали:
LK>Я не в курсе, увы. И задачу вижу в первый раз. LK>Считаю, что правильный ответ: родитель — квадрат. LK>Можно узнать правильный ответ?
Вот определение наследования:
B пронаследован от А тогда и только тогда, когда для любого экземпляра B верно, что
1) он является экземпляром А (B подмножество А)
2) что модифицирующие операции, определенные в А не выводят экземпляр В из класса В (операции должны быть замкнуты).
Ваш пример нарушает пункт 1 определения наследования, так как любой прямоугольник — это не квадрат. Все ровно наоборот. Если делать наоборот — то нарушится пункт 2, так как, например, операция прямоугольника изменяющая его ширину, выводит квадрат из класса квадратов. А изменять семантику этой операции тоже нельзя — тогда нарушится принцип подстановки Лисков. Вот этот принцип:
Если B пронаследован от А, то любая программа, работающая с А, должна корректно работать и с экземплярами В.
Другими словами, если вместо А поставить экземпляр В то любая корректно написанная программа должна продолжить работать корректно, или наследование применено не по назначению. Этот же принцип нарушается и при вашем решении — программа, работающая с базовым классом "квадрат" предполагает, что стороны у этой фигуры равны. Не составит труда придумать такую программу, работающую с квадратом, штоб она вела себя некорректно при замене квадрата на прямоугольник.
Так что правильный ответ — они вообще не связаны наследованием. В этом суть всех подобных задач (круг — эллипс, дествительное — комплексное число, итд). Правильно их решить может только человек, знакомый с теорией.
Здравствуйте, eao197, Вы писали:
E>Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>>Это именно то. То есть правильный ответ, пожалуй, не Мартин, а Лискова.
E>По-моему, фамилия Лисков не склоняется. По крайней мере везде в русскоязычной литературе было написано "принцип Лисков (Барбара Лисков)", а не "принцип Лисковой"
Фамилии то склоняются... но только мужские.
т.е. если бы это был мужчина, то принцип Лискова
(с) правила русского языка.
Хорошо видно по корейским фамилиям — Ким Наталье, Киму Антону.
Здравствуйте, okurietz, Вы писали:
ANS>>>Это именно то. То есть правильный ответ, пожалуй, не Мартин, а Лискова.
E>>По-моему, фамилия Лисков не склоняется. По крайней мере везде в русскоязычной литературе было написано "принцип Лисков (Барбара Лисков)", а не "принцип Лисковой" O>Фамилии то склоняются... но только мужские. O>т.е. если бы это был мужчина, то принцип Лискова O>(с) правила русского языка.
O>Хорошо видно по корейским фамилиям — Ким Наталье, Киму Антону.
Н-да. Век живи, век учись, а результат зараннее определён
Буду знать.