Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Кстати, этой проблемы с нарушением инвариантов не будет если не будет мутирующих методов.
И появится другая проблема. "Const OOП" с константными методами лишает объекты состояния, и в результате не позволяет применять объекты для полноценного моделирования. Проблемы начнутся с самого обычного случая, когда ваши объекты циклически ссылаются друг на друга — вызов такого "немутирующего" метода рвет связи. В том смысле, что все продолжат ссылаться на старый, а не на новый объект.
Короче, это безусловно некий подход, но он не только решает проблемы, но также их и создает — только другие.
Здравствуйте, AndrewVK, Вы писали:
AVK>Классический косяк, вызванный тем, что обычно наследование вызывает и наследование интерфейсов, и наследование реализаций.
Хм... Таки под наследованием (inheritance, generalization) понимается именно наследование реализации. Когда имеется ввиду наследование интерфейсов — говорят о реализации (implementation). ИМХО.
Здравствуйте, Gaperton, Вы писали:
G>Вот определение наследования: G>B пронаследован от А тогда и только тогда, когда для любого экземпляра B верно, что G>1) он является экземпляром А (B подмножество А) G>2) что модифицирующие операции, определенные в А не выводят экземпляр В из класса В (операции должны быть замкнуты).
Можно поинтересоваться о возникновении п.2? ИМХО, к определению отношения "наследование" он имеет слабое отношение.
G>Ваш пример нарушает пункт 1 определения наследования, так как любой прямоугольник — это не квадрат.
Только в том плане, что может задаваться двумя длинами, и может менять размеры сторон независимо друг от друга. Ключевое слово может. Т.е. прямоугольник, как это не абсурдно звучит, можно рассмотреть как специализацию "квадрата".
G>Все ровно наоборот.
Угу... Т.к. квадрат "прикинуться" прямоугольником не может.
G>Если делать наоборот — то нарушится пункт 2, так как, например, операция прямоугольника изменяющая его ширину, выводит квадрат из класса квадратов. А изменять семантику этой операции тоже нельзя — тогда нарушится принцип подстановки Лисков. Вот этот принцип: G>Если B пронаследован от А, то любая программа, работающая с А, должна корректно работать и с экземплярами В.
G>Другими словами, если вместо А поставить экземпляр В то любая корректно написанная программа должна продолжить работать корректно, или наследование применено не по назначению. Этот же принцип нарушается и при вашем решении — программа, работающая с базовым классом "квадрат" предполагает, что стороны у этой фигуры равны.
Угу... и что, у прямоугольника стороны обязаны быть не равны?! Или A.get_Size не может быть переопределена в B.get_Size таким образом, что B.Width = B.Height? Другое дело, что вообще говоря, это несколько... коряво что ли. Но тем не менее. Программа будет корректно работать. Так что, ИМХО, вариант S<-R, в общем случае, ППЛ не нарушает... в отличие от варианта R<-S.
G>Не составит труда придумать такую программу, работающую с квадратом, штоб она вела себя некорректно при замене квадрата на прямоугольник.
Сильно сомневаюсь... Все зависит от контракта квадрата, и его реализации в прямоугольнике.
G>Так что правильный ответ — они вообще не связаны наследованием. В этом суть всех подобных задач (круг — эллипс, дествительное — комплексное число, итд). Правильно их решить может только человек, знакомый с теорией.
Вообще говоря, основной вопрос в задаче — почему
А мой, вопрос — кто автор?
Ещё раз повторюсь: Задача ставится в терминах OOA.
Здравствуйте, gbear, Вы писали:
G>Здравствуйте, Gaperton, Вы писали:
G>>Вот определение наследования: G>>B пронаследован от А тогда и только тогда, когда для любого экземпляра B верно, что G>>1) он является экземпляром А (B подмножество А) G>>2) что модифицирующие операции, определенные в А не выводят экземпляр В из класса В (операции должны быть замкнуты).
G>Можно поинтересоваться о возникновении п.2? ИМХО, к определению отношения "наследование" он имеет слабое отношение.
Пункт 2 возникает из простого факта, что модифицирующая операция (метод) не может изменить тип (класс) объекта, т.е. является замкнутой. Так устроены все строготипизированные ОО языки, и абсолютное большинство динамически типизированых. К определению отношения "наследование" он имеет самое прямое отношение, так является частью этого определения в теории типа.
G>>Ваш пример нарушает пункт 1 определения наследования, так как любой прямоугольник — это не квадрат.
G> Только в том плане, что может задаваться двумя длинами, и может менять размеры сторон независимо друг от друга. Ключевое слово может. Т.е. прямоугольник, как это не абсурдно звучит, можно рассмотреть как специализацию "квадрата".
Любой квадрат является прямоугольником. Некоторые прямоугольники являются квадратами. Следовательно, множество всевозможных квадратов является подмножеством множества прямоугольников. Ключевое слово — подмножество.
G>>Все ровно наоборот. G>Угу... Т.к. квадрат "прикинуться" прямоугольником не может.
Все ровно наоборот. Квадрат всегда является прямоугольником. Пятый класс вторая четверть.
G>>Другими словами, если вместо А поставить экземпляр В то любая корректно написанная программа должна продолжить работать корректно, или наследование применено не по назначению. Этот же принцип нарушается и при вашем решении — программа, работающая с базовым классом "квадрат" предполагает, что стороны у этой фигуры равны.
G> Угу... и что, у прямоугольника стороны обязаны быть не равны?!
Нет. G>Или A.get_Size не может быть переопределена в B.get_Size таким образом, что B.Width = B.Height? Другое дело, что вообще говоря, это несколько... коряво что ли. Но тем не менее. Программа будет корректно работать.
Не будет программа корректно работать. Если базовый класс — прямоугольник, то следующая программа сломается при замене его на квадрат:
figure.SetHeight( 5 );
figure.SetLehgth( 10 );
value = figure.GetHeight() / ( figure.GetLength() - figure.GetHeight() ); // деление на ноль в случае квадрата
G>Так что, ИМХО, вариант S<-R, в общем случае, ППЛ не нарушает... в отличие от варианта R<-S. G>>Не составит труда придумать такую программу, работающую с квадратом, штоб она вела себя некорректно при замене квадрата на прямоугольник. G>Сильно сомневаюсь... Все зависит от контракта квадрата, и его реализации в прямоугольнике.
Совершенно неважно. Даже если удастся в конкретном случае извернуться, то в результате получится хрупкий дизайн, который разрушит всю систему при добавлении операций к квадрату и прямоугольнику. Нарушение первого пункта слишком фундаментально, и в любом случае с рук не сойдет.
Теперь о примере. Если базовый класс — квадрат, то следующая программа перестанет работать, если ей подпихнуть figure в виде прямоугольника со сторонами 5 и 10:
Вариант 1: Вы пытаетесь извернуться, и ввести отдельный метод для взятия длины ребра квадрата. Вот незадача, для большинства прямоугольников (которые не квадраты) он вести себя корректно не может, и будет бросать exception. Вуаля.
size = figure.GetSquareSize();
Все остальные варианты: Допустим, он не бросает exception, а возвращает одну из сторон. Тогда вы нарушите инвариант базового класса, который состоит вот в чем: GetSquareSize() ^ 2 == GetArea(). Мне написать программу, которая будет себя вести некорректно, или вы это сможете сделать сами? То же самое касается и всех остальных вариантов — всегда будет возможность подсунуть такой прямоугольник, который нарушит инвариант базового класса.
Вы почитайте старую ветку, ссылку на которую я давал — там очень подробно все обсуждалось.
G>>Так что правильный ответ — они вообще не связаны наследованием. В этом суть всех подобных задач (круг — эллипс, дествительное — комплексное число, итд). Правильно их решить может только человек, знакомый с теорией. G>Вообще говоря, основной вопрос в задаче — почему
В силу природы вещей.
G>А мой, вопрос — кто автор?
Скорее всего — Барбара Лисков.
G>Ещё раз повторюсь: Задача ставится в терминах OOA.
Ну да, а я о чем по вашему говорю?
Здравствуйте, Gaperton, Вы писали:
G>>Можно поинтересоваться о возникновении п.2? ИМХО, к определению отношения "наследование" он имеет слабое отношение.
G>Пункт 2 возникает из простого факта, что модифицирующая операция (метод) не может изменить тип (класс) объекта, т.е. является замкнутой. Так устроены все строготипизированные ОО языки, и абсолютное большинство динамически типизированых. К определению отношения "наследование" он имеет самое прямое отношение, так является частью этого определения в теории типа.
Спасибо, я понял, что имеется ввиду.
G>>>Ваш пример нарушает пункт 1 определения наследования, так как любой прямоугольник — это не квадрат.
G>> Только в том плане, что может задаваться двумя длинами, и может менять размеры сторон независимо друг от друга. Ключевое слово может. Т.е. прямоугольник, как это не абсурдно звучит, можно рассмотреть как специализацию "квадрата".
G>Любой квадрат является прямоугольником. Некоторые прямоугольники являются квадратами. Следовательно, множество всевозможных квадратов является подмножеством множества прямоугольников. Ключевое слово — подмножество.
С точки зрения геометрии — безусловно. С точки зрения рассмотрения "поведений" этих сущностей — именно прямоугольники — подмножество квадратов. См. чуть ниже.
G>>>Все ровно наоборот. G>>Угу... Т.к. квадрат "прикинуться" прямоугольником не может. G>Все ровно наоборот. Квадрат всегда является прямоугольником. Пятый класс вторая четверть.
Геометрия рулит . Но "квадрат": задается одним размером, размеры "сторон" обязаны быть равными; "прямоугольник": может задаваться одним размером, размеры сторон могут быть равными. Т.о. — с точки зрения поведений — "квадрат" базовая, по отношению к "прямоугольник", сущность, т.к. сущность "прямоугольник" реализует дополнительное, по отношению к "квадрат" поведение... а именно: может задаваться двумя размерами, размеры сторон могут быть не равны.
G>>>Другими словами, если вместо А поставить экземпляр В то любая корректно написанная программа должна продолжить работать корректно, или наследование применено не по назначению. Этот же принцип нарушается и при вашем решении — программа, работающая с базовым классом "квадрат" предполагает, что стороны у этой фигуры равны.
G>Не будет программа корректно работать. Если базовый класс — прямоугольник, то следующая программа сломается при замене его на квадрат:
Мы о чем?! Яж не спорю о варианте R<-S... Я говорю что при варианте S<-R, в общем случае ППЛ не нарушается.
G>>Так что, ИМХО, вариант S<-R, в общем случае, ППЛ не нарушает... в отличие от варианта R<-S.
G>>>Не составит труда придумать такую программу, работающую с квадратом, штоб она вела себя некорректно при замене квадрата на прямоугольник. G>>Сильно сомневаюсь... Все зависит от контракта квадрата, и его реализации в прямоугольнике. G>Совершенно неважно. Даже если удастся в конкретном случае извернуться, то в результате получится хрупкий дизайн, который разрушит всю систему при добавлении операций к квадрату и прямоугольнику. Нарушение первого пункта слишком фундаментально, и в любом случае с рук не сойдет.
Хм... Вы утверждаете, что квадрат теоритически может обладать таким поведением, которое не реализуемо (принципиально) в прямоугольнике?
G>Теперь о примере. Если базовый класс — квадрат, то следующая программа перестанет работать, если ей подпихнуть figure в виде прямоугольника со сторонами 5 и 10:
G>Вариант 1: Вы пытаетесь извернуться, и ввести отдельный метод для взятия длины ребра квадрата. Вот незадача, для большинства прямоугольников (которые не квадраты) он вести себя корректно не может, и будет бросать exception. Вуаля. G>
G>size = figure.GetSquareSize();
G>
Хм... Смотрим:
class S
{
virtual int Size
{
get{return _size;}
set{_size = value;}
}
virtual int Area
{
return (_size * _size);
}
}
class R: S
{
int Height
{
get{return base.Size;}
set{base.Size = value;}
}
int Width
{
get{retunr _width;}
set{_width = value;}
}
override int Size
{
//Может быть перекрыт как угодно... напримет так.get
{
_width = base.Size;
return base.Size;
}
set
{
_width = base.Size = value;
}
}override int Area
{
return base.Size * _width;
}
}
Так что мне не совсем понятно, о чем идет речь... Например, о каком специальном методе "взятия длины ребра квадрата" мы говорим? Следуя принципу достаточности контракта, этот метод должне быть в контракте квадрата... а вот свойств "ширина"/"высота" в контракте квадрата, по уму, быть не должно.
G>Все остальные варианты: Допустим, он не бросает exception, а возвращает одну из сторон. Тогда вы нарушите инвариант базового класса, который состоит вот в чем: GetSquareSize() ^ 2 == GetArea().
См. выше... Идея состоит в том, что если агрегат работает с прямоугольником через интерфейс квадрата — прямоугольник, для такого агрегата станет "квадратом"... Он может им стать. Всё поведение квадрата реализуемо в прямоугольнике.
G>Мне написать программу, которая будет себя вести некорректно, или вы это сможете сделать сами? То же самое касается и всех остальных вариантов — всегда будет возможность подсунуть такой прямоугольник, который нарушит инвариант базового класса.
Ещё раз... Все это "лечится" реализацией.
G>Вы почитайте старую ветку, ссылку на которую я давал — там очень подробно все обсуждалось.
Читал... Про вариант S<-R мало убедительного.
G>>Вообще говоря, основной вопрос в задаче — почему G>В силу природы вещей.
G>>А мой, вопрос — кто автор? G>Скорее всего — Барбара Лисков.
Вряд ли... Именно потому, что все рассуждение ведутся на уровне конкретных реализаций. Т.е. как мимнимум на уровне OOD...
G>>Ещё раз повторюсь: Задача ставится в терминах OOA. G>Ну да, а я о чем по вашему говорю?
Тоже, как минимум на уровне OOD... Я уже говорил о том, что, если так можно выразиться, практический смысл задачи — выявление интерфейсных сущностей на этапе OOA.
Здравствуйте, gbear, Вы писали:
G>День добрый...
G>Сорри, за возможный оффтоп, но вряд ли кто-либо кроме участников этого форума знает ответ.
G>Вопрос такой... Никто не в курсе, кто автор задачки "про квадрат и прямоугольник" (что-то типа):
G>Дано две сущности: квадрат и прямоугольник. Они обладают следующим поведением:
G>1. Предоставляют информацию о своих размерах. G>2. Могут изменять свои размеры. G>3. Предоставляют информацию о своей площади.
G>Вопрос: Кто из них родитель, а кто предок? Почему?
Вообще, можно сделать и так, и так. Вся загвоздка в возвращаемых параметрах. Если сначала описали сущность квадрата, у которого функция размера возвращает только длину одной стороны, то переопределить ее для прямоугольника будет сложновато...
Здравствуйте, OnThink, Вы писали:
OT>Здравствуйте, gbear, Вы писали:
G>>Вопрос: Кто из них родитель, а кто предок? Почему?[/i]
OT>никто не родитель: OT>круг не является квадратом OT>квадрат не является кругом OT>родителем должен быть абстракный объект — фигура
Квадрат — частный случай прямоугольника (впрочем, как и ромба...).
Здравствуйте, gbear, Вы писали:
G>Хм... Смотрим:
G>
G>class S
G>{
G> virtual int Size
G> {
G> get{return _size;}
G> set{_size = value;}
G> }
G> virtual int Area
G> {
G> return (_size * _size);
G> }
G>}
G>class R: S
G>{
G> int Height
G> {
G> get{return base.Size;}
G> set{base.Size = value;}
G> }
G> int Width
G> {
G> get{retunr _width;}
G> set{_width = value;}
G> }
G>override int Size
G> {
G> //Может быть перекрыт как угодно... напримет так.
G> get
G> {
G> _width = base.Size;
G> return base.Size;
G> }
G> set
G> {
G> _width = base.Size = value;
G> }
G> }
G> override int Area
G> {
G> return base.Size * _width;
G> }
G>}
G>
G>Так что мне не совсем понятно, о чем идет речь... Например, о каком специальном методе "взятия длины ребра квадрата" мы говорим? Следуя принципу достаточности контракта, этот метод должне быть в контракте квадрата... а вот свойств "ширина"/"высота" в контракте квадрата, по уму, быть не должно.
Ваша реализация нарушает инвариант базового класса, нарушая таким образом принцип подстановки Лисков. Конкретнее, вот этот код
int a1 = figure.Area();
int tmp = figure.Size();
if( a1 != figure.Area() )
crash_system();
сработает для квадрата, но завалит систему, если figure является прямоугольником с неравными сторонами.
Геометрия, как вы говорили, рулит. Ни при каких обстоятельствах не стоит нарушать пункт 1 определения наследования, ничего хорошего из этого не выйдет. Попытаетесь еще раз?
Здравствуйте, gbear, Вы писали:
G>>Вот определение наследования: G>>B пронаследован от А тогда и только тогда, когда для любого экземпляра B верно, что G>>1) он является экземпляром А (B подмножество А) G>>2) что модифицирующие операции, определенные в А не выводят экземпляр В из класса В (операции должны быть замкнуты).
G>Можно поинтересоваться о возникновении п.2? ИМХО, к определению отношения "наследование" он имеет слабое отношение.
по моему там (в пункте 2) было еще что-то об недопустимости "усиления ограничений" или как-то так звучит.
т.е. если класс А имеет виртуальную функцию, в которой есть ограничение на входной параметр С от 0 до 5, то клаcc Б унаследованный от А не может накладывать более жесткие ограничения.
для класса Б:
0 < C < 10 — верно
0 < C < 2 — неверно
Здравствуйте, Oleg A. Bachin, Вы писали:
OAB>Здравствуйте, gbear, Вы писали:
G>>>Вот определение наследования: G>>>B пронаследован от А тогда и только тогда, когда для любого экземпляра B верно, что G>>>1) он является экземпляром А (B подмножество А) G>>>2) что модифицирующие операции, определенные в А не выводят экземпляр В из класса В (операции должны быть замкнуты).
G>>Можно поинтересоваться о возникновении п.2? ИМХО, к определению отношения "наследование" он имеет слабое отношение.
OAB>по моему там (в пункте 2) было еще что-то об недопустимости "усиления ограничений" или как-то так звучит. OAB>т.е. если класс А имеет виртуальную функцию, в которой есть ограничение на входной параметр С от 0 до 5, то клаcc Б унаследованный от А не может накладывать более жесткие ограничения. OAB>для класса Б: OAB>0 < C < 10 — верно OAB>0 < C < 2 — неверно
Да, на самом деле там было жестко. Так накладывались ограничения не предусловия и постусловия для каждого метода А, перекрываемого в Б. Предусловие не может быть более сильным, а постусловие не может быть более слабым. Что-то в таком духе.
Я обычно заменяю это правилом подстановки Лисков — так проще.
Здравствуйте, Gaperton, Вы писали:
G>Я обычно заменяю это правилом подстановки Лисков — так проще.
аналогично
просто уже все это на уровне посприятия, но после прочтения оставалось ощущение какой-то недосказанности...
попытался вспомнить чего не хватает — потом сформулировал
Здравствуйте, Gaperton, Вы писали:
G>Ваша реализация нарушает инвариант базового класса, нарушая таким образом принцип подстановки Лисков. Конкретнее, вот этот код G>
G>сработает для квадрата, но завалит систему, если figure является прямоугольником с неравными сторонами.
Лишь по той простой причине, что ф-ция расчета площади виртуальна. Что, вообще говоря, сааавсем не обязательно.
G>Геометрия, как вы говорили, рулит. Ни при каких обстоятельствах не стоит нарушать пункт 1 определения наследования, ничего хорошего из этого не выйдет. Попытаетесь еще раз?
А смысл, если Вы до сих пор при виде варианта S<-R "тыкаете" в п.1. С чего Вы взяли что "квадрат" подмножество "прямоугольников"?! Только лишь на том, основании что любой квадрат, с т.з. геометрии, прямоугольник?! Но ведь тип-то, определяется реализуемым поведением... разве не так? И именно из этих соображений строятся все иерархии наследования — реализуемое поведение специализируется и расширяется вниз по иерархии. Т.е. говоря о подмножествах типов — мы говорим о подмножествах реализуемых ими поведений. Согласны? Иначе я не совсем понимаю, что Вы понимаете под п.1.
Второй момент — бессмысленно, имхо, рассуждать вообще о любом агрегате... Но, для варианта S<-R можно утверждать, что для для любого агрегата A, агригирующего S, всегда найдется такая реализация S и R:S, при которой: контракты S и R:S достаточны; инвариант S не нарушается A; R не противоречит ППЛ. С этим тоже не согласны? Причем имеенно только для варианта S<-R... Для варианта R<-S такого утвеждать нельзя.
Другое дело, что можно найти и такой агрегат, для которого вариант S<-R будет лишён смысла... не в том, плане что для него не будут выполняться выше указанные условия. А в том, что он нам ничего, кроме "лишней" связности, не даст.
Причем, рассуждая так, мы с вами автоматически "переносимся" в OOD, решая, совсем другую задачу
На уровне OOA у нас ещё нет даже формально описанного поведения — т.е. выраженного в терминах состояния и передачи сообщений. Оно у нас пока ещё описано неформально... простым человеческим языком, так сказать. Но уже на этом этапе, можно с изрядной долей уверенности утверждать, что классы, реализующие сущности с подобным (не подобным, описаному в задаче, а подобным друг другу) поведением, будут находится на одином уровне в иерархии классов. Просто протому, что смысл отношения наследования заключается даже не столько в специализации поведения, сколько в его расширеннии. Что для нас означает, что на N+1-ом уровне нам, собственно, нечего расширять... у нас нет дополнительного поведения. Мы можем лищь специализировать поведение определенное на N-ом уровне иерархии. При этом, мы должны быть точно уверены в том, что порождаемая связность — оправданы в нашем дизайне. Что, в общем случае, не очевидно.
Возвращаясь к наши баранам, мы не можем утвержать наличие/отсутвие дополнительного поведения у какой-либо из рассматриваемых сущностей без рассмотрения конкретного агрегата (которого на этапе OOA тоже может и не быть выявлено в надлежащей формализации). Собственно, по этому и утверждается, что задача не имеет конкретного правильного решения. Есть лишь теоритически верное предпосылка к тому, что бы определить некую "интерфейсную" сущность.
Здравствуйте, gbear, Вы писали:
G>Здравствуйте, Gaperton, Вы писали:
G>>Ваша реализация нарушает инвариант базового класса, нарушая таким образом принцип подстановки Лисков. Конкретнее, вот этот код G>>
G>>сработает для квадрата, но завалит систему, если figure является прямоугольником с неравными сторонами.
G> Лишь по той простой причине, что ф-ция расчета площади виртуальна. Что, вообще говоря, сааавсем не обязательно.
Ну-ну. Для любого вашего варианта, какой бы вы ни придумали, будет существовать такая программа, которая будет вести себя некорректно в случае прямоугольника. Если вы это до сих пор не понимаете, то видимо, не поймете уже никогда.
G>>Геометрия, как вы говорили, рулит. Ни при каких обстоятельствах не стоит нарушать пункт 1 определения наследования, ничего хорошего из этого не выйдет. Попытаетесь еще раз? G> А смысл, если Вы до сих пор при виде варианта S<-R "тыкаете" в п.1.
Смысл? Для вас смысл очень простой — если вы так уверены в себе, то я предлагаю вам на мне заработать. Ставлю, скажем, 50 баксов. Вы даете очередную реализацию — я пишу программу, которая ведет себя по разному для прямоугольника и квадрата. У меня получается — вы переводите мне 50 долларов. Почтовым переводом. Не получается — это делаю я. Выбираем арбитра — я предлагаю Синклера. Ну что, deal?
G>С чего Вы взяли что "квадрат" подмножество "прямоугольников"?!
Вы, должно быть, шутите, мистер Фейнман? С того, что у вас в условии заданы алгоритмы рассчета площади и публичные порперти, которые однозначно задают именно "квадрат" и именно "прямоугольник". Не существует других фигур, площадь которых рассчитывается по заданной схеме. Отсюда следует, что мы имеем дело именно с означенными геометрическими фигурами, а не сферическими конями в вакууме.
С того, что при проектировании (вы так на ООА напираете, что даже странно) вы прекрасено знаете, что имеете дело именно с квадратом и именно с прямоугольником. В принципе, даже последнего достаточно.
G>Собственно, по этому и утверждается, что задача не имеет конкретного правильного решения. Есть лишь теоритически верное предпосылка к тому, что бы определить некую "интерфейсную" сущность.
Она имеет вполне конкретные неправильные решения. И одно из них — ваше.
Здравствуйте, mibe, Вы писали:
M>А еще бывают языки типа cecil где класс можно декларативно определить (типа квадрат это прямоугольник у которого длина=ширина) и конкретный объект классифицируется динамически на основе такого определения.
Я бы и на обычном языке программирования не вводил бы отдельный класс для квадрата. Я бы для прямоугольника ввел операцию, типа FixAspectRatio(double ratio), и при изменении любой из сторон затем вычислял другую. Соответственно, для конкретной нужды в квадрате FixSpectRatio(1).
И далее:
bool IsQuadrant { return GetAspecRation()==1.0; }
Здравствуйте, Gaperton, Вы писали:
G>Ну-ну. Для любого вашего варианта, какой бы вы ни придумали, будет существовать такая программа, которая будет вести себя некорректно в случае прямоугольника. Если вы это до сих пор не понимаете, то видимо, не поймете уже никогда.
Так же, будет существовать и программа (агрегат), которая будет вести себя корректно. Причем (в который раз уже повторяюсь) это рассуждения из области OOD... И, как Вы сами, прекрасно знаете, если мы говорим не о библиотеке, сначала выявляются и описываются агрегаты, а потом уже все остальное. Или у Вас все наоборот? Если же мы имеем ввиду "программу", как библиотеку, то мы, как авторы этой библиотеки, вполне можем наложить ограничения а типы агрегатов использующих её. Разве нет?
G>>>Геометрия, как вы говорили, рулит. Ни при каких обстоятельствах не стоит нарушать пункт 1 определения наследования, ничего хорошего из этого не выйдет. Попытаетесь еще раз? G>> А смысл, если Вы до сих пор при виде варианта S<-R "тыкаете" в п.1.
G>Смысл? Для вас смысл очень простой — если вы так уверены в себе, то я предлагаю вам на мне заработать. Ставлю, скажем, 50 баксов. Вы даете очередную реализацию — я пишу программу, которая ведет себя по разному для прямоугольника и квадрата. У меня получается — вы переводите мне 50 долларов. Почтовым переводом. Не получается — это делаю я. Выбираем арбитра — я предлагаю Синклера. Ну что, deal?
Ну не красиво же... право слово.
Второй момент — бессмысленно, имхо, рассуждать вообще о любом агрегате... Но, для варианта S<-R можно утверждать, что для для любого агрегата A, агригирующего S, всегда найдется такая реализация S и R:S, при которой: контракты S и R:S достаточны; инвариант S не нарушается A; R не противоречит ППЛ. С этим тоже не согласны? Причем имеенно только для варианта S<-R... Для варианта R<-S такого утвеждать нельзя.
Угу... Это я Вам сказал, в предыдущем посте. И что я слышу?! Мне вот просто интересно, что Вы ожидали услышать в ответ?
G>>С чего Вы взяли что "квадрат" подмножество "прямоугольников"?!
G>Вы, должно быть, шутите, мистер Фейнман? С того, что у вас в условии заданы алгоритмы рассчета площади и публичные порперти, которые однозначно задают именно "квадрат" и именно "прямоугольник". Не существует других фигур, площадь которых рассчитывается по заданной схеме. Отсюда следует, что мы имеем дело именно с означенными геометрическими фигурами, а не сферическими конями в вакууме.
Шучу? Шучу? Что, черт подери, я только что ляпнул? Вы разве не согласны с тем, что тип — суть поведение? Разве Вы не согласны с тем, что "вниз по иерархии" реализуемое типами поведение должно расширяться? Как минимум — специализироваться? Так объясните мне — почему, если все поведение квадрата, реализуемо прямоугольником, я не могу сказать, что прямоугольник "подтип" квадрата? Только лишь на том, основании, что с т.з. геометрии это не так?! Или может быть на том основании, что, вообще говоря, в определенный момент объект-прямоугольник может находится вне состояний объекта-квадрата. Вас это пугает? Так ведь мы с Вами, как Вы верно подметили, не о шаровых (так смешней) конях рассуждаем... Спускаетесь до OOD — извольте агрегат. Вам что, тяжело представить себе, как Вы говорите, программу, которой эти нюансы, образно выражаясь, сугубо фиалетовы?
G>С того, что при проектировании (вы так на ООА напираете, что даже странно) вы прекрасено знаете, что имеете дело именно с квадратом и именно с прямоугольником. В принципе, даже последнего достаточно.
И что с того?! Вас послушать, так получается что я принципиально не могу связывать наследованием такие сущности как квадрат (дался он мне) и круг. Просто на том основаннии, что. Так что ли?
G>>Собственно, по этому и утверждается, что задача не имеет конкретного правильного решения. Есть лишь теоритически верное предпосылка к тому, что бы определить некую "интерфейсную" сущность.
G>Она имеет вполне конкретные неправильные решения. И одно из них — ваше.
Конкретно, неправильное решение, это вариант R<-S. Для варианта S<-R существуют агрегаты, и такие реализации S и R:S, при которых... и т.д. Ну Вы поняли
Здравствуйте, gbear, Вы писали:
G>Шучу? Шучу? Что, черт подери, я только что ляпнул? Вы разве не согласны с тем, что тип — суть поведение? Разве Вы не согласны с тем, что "вниз по иерархии" реализуемое типами поведение должно расширяться? Как минимум — специализироваться? Так объясните мне — почему, если все поведение квадрата, реализуемо прямоугольником, я не могу сказать, что прямоугольник "подтип" квадрата?
Нет. Гапертон уже с десяток постов, как продемонстрировал, что и у прямоугольника и у квадрата есть поведения, которые невозможно корректно реализовать в другой фигуре.
G> И что с того?! Вас послушать, так получается что я принципиально не могу связывать наследованием такие сущности как квадрат (дался он мне) и круг. Просто на том основаннии, что. Так что ли?
Нет, технически, конечно, можно. Но с точки зрения OOA это бред, т.к. как только ты введешь в одну из сущностей специфичное для нее поведение, как наследник не сможет его корректно реализовать.
G>Конкретно, неправильное решение, это вариант R<-S. Для варианта S<-R существуют агрегаты, и такие реализации S и R:S, при которых... и т.д. Ну Вы поняли
Не существует таких реализаций. Максимум, на который можно рассчитывать — это наследование обоих от единого базового класса/интерфейса. При этом он будет настолько убогим, что не сможет иметь практической ценности.
... << RSDN@Home 1.1.4 beta 5 rev. 395>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Нет. Гапертон уже с десяток постов, как продемонстрировал, что и у прямоугольника и у квадрата есть поведения, которые невозможно корректно реализовать в другой фигуре.
Пример поведения реализуемого в квадрате, и теоритически нереализуемого в прямогугольнике в студию. После этого и продолжим разговор.
Здравствуйте, gbear, Вы писали:
G>Пример поведения реализуемого в квадрате, и теоритически нереализуемого в прямогугольнике в студию. После этого и продолжим разговор.
Получение круга, который касается всех четырех сторон. Пойдет?
Здравствуйте, gbear, Вы писали:
G>Здравствуйте, Gaperton, Вы писали:
G>>Ну-ну. Для любого вашего варианта, какой бы вы ни придумали, будет существовать такая программа, которая будет вести себя некорректно в случае прямоугольника. Если вы это до сих пор не понимаете, то видимо, не поймете уже никогда.
G> Так же, будет существовать и программа (агрегат), которая будет вести себя корректно.
Принцип подстановки Лисков, которому должны удовлетворять подтипы, требует корректного поведения от любой программы при замене типа на подтип. Чувствуете разницу между "любой" и "будет существовать"?
G>>>>Геометрия, как вы говорили, рулит. Ни при каких обстоятельствах не стоит нарушать пункт 1 определения наследования, ничего хорошего из этого не выйдет. Попытаетесь еще раз? G>>> А смысл, если Вы до сих пор при виде варианта S<-R "тыкаете" в п.1.
G>>Смысл? Для вас смысл очень простой — если вы так уверены в себе, то я предлагаю вам на мне заработать. Ставлю, скажем, 50 баксов. Вы даете очередную реализацию — я пишу программу, которая ведет себя по разному для прямоугольника и квадрата. У меня получается — вы переводите мне 50 долларов. Почтовым переводом. Не получается — это делаю я. Выбираем арбитра — я предлагаю Синклера. Ну что, deal?
G> Ну не красиво же... право слово.
Вы меня убиваете, право слово. Я вам тут считай даром 50 баксов предлагаю , само по себе нивираятна блаародный и красивый поступок, вот. Причем все честно — Синклер человек строгих правил и не допустит тут никакого жульничества. А вы, можно сказать, раздающему, то есть мне, прикуп в морду швыряете. За что?!
G>
G>Второй момент — бессмысленно, имхо, рассуждать вообще о любом агрегате... Но, для варианта S<-R можно утверждать, что для для любого агрегата A, агригирующего S, всегда найдется такая реализация S и R:S, при которой: контракты S и R:S достаточны; инвариант S не нарушается A; R не противоречит ППЛ. С этим тоже не согласны?
1) ППЛ сам по себе предполагает, что при фиксированных R и S все возможные программы А будут работать корректно, в том смысле, что с точки зрения А (еще раз — совершенно любого А для фиксированных S и R) нет никакой разницы между S и его подклассом R.
2) Вы пишете, что если для заданых S и R существует хотя бы один такой А, что он не может различить S от R, то выполняется ППЛ. Это, очевидно неправда — см пункт 1. Из того, что заданным свойстом обладает единственный элемент множества, никак не следует, что им обладают все элементы, а именно этого требует ППЛ. Вы можете задаться вопросом: почему? Это уже другая история, но можем поговорить и об этом.
G>Угу... Это я Вам сказал, в предыдущем посте. И что я слышу?! Мне вот просто интересно, что Вы ожидали услышать в ответ?
Я ожидал услышать в ответ: я согласен. Вот вам моя программа. И, чуть позже: куда переводить деньги? 50 баксов, сами понимаете, не лишние.
G>>>С чего Вы взяли что "квадрат" подмножество "прямоугольников"?!
G>>Вы, должно быть, шутите, мистер Фейнман? С того, что у вас в условии заданы алгоритмы рассчета площади и публичные порперти, которые однозначно задают именно "квадрат" и именно "прямоугольник". Не существует других фигур, площадь которых рассчитывается по заданной схеме. Отсюда следует, что мы имеем дело именно с означенными геометрическими фигурами, а не сферическими конями в вакууме.
G>Шучу? Шучу? Что, черт подери, я только что ляпнул? Вы разве не согласны с тем, что тип — суть поведение? Разве Вы не согласны с тем, что "вниз по иерархии" реализуемое типами поведение должно расширяться? Как минимум — специализироваться? Так объясните мне — почему, если все поведение квадрата, реализуемо прямоугольником, я не могу сказать, что прямоугольник "подтип" квадрата?
Слушайте, я вам привел определение подтипа из теории типа. Прямоугольник, определенный так как это сделано в задаче, не может являться подтипом квадрата. Он нарушает инварианты базового класса, или принцип подстановки Лисков, что по сути одно и то же. Поэтому я не могу сказать, что прямоугольник подтип квадрата. Но вам — можно.
G>Вас это пугает? Так ведь мы с Вами, как Вы верно подметили, не о шаровых (так смешней) конях рассуждаем... Спускаетесь до OOD — извольте агрегат. Вам что, тяжело представить себе, как Вы говорите, программу, которой эти нюансы, образно выражаясь, сугубо фиалетовы?
Нет, не тяжело, я видел в жизни много плохо спроектированых систем. Мне будет тяжело такую программу поддерживать и развивать. В определенный момент (который довольно скоро наступит) ее придется просто выбросить (так будет существенно дешевле) как ярко выраженый образчик хрупкого дизайна, трещащий по швам при любой модификации.
В реальной жизни шутки с принцим Лисков и определением подтипа обходятся очень дорого, особенно для больших и сложных систем. В лучшем случае обойдется раздуванием кода на ровном месте и возрастанием количества дефектов. В худшем случае — этот рост будет катастрофическим. Видел примеры в том числе и на собственном коде.
G>>С того, что при проектировании (вы так на ООА напираете, что даже странно) вы прекрасено знаете, что имеете дело именно с квадратом и именно с прямоугольником. В принципе, даже последнего достаточно.
G> И что с того?! Вас послушать, так получается что я принципиально не могу связывать наследованием такие сущности как квадрат (дался он мне) и круг. Просто на том основаннии, что. Так что ли?
Принципиально вы можете делать все что угодно, кто же вам запретит. Речь идет не о том, что вы можете, а о том, что вы считаете даже не допустимым — а хорошим, правильным. Сделаете плохо — сами потом пожалеете. Ну или ваши коллеги пожалеют, кому модифицировать систему придется .
G>>>Собственно, по этому и утверждается, что задача не имеет конкретного правильного решения. Есть лишь теоритически верное предпосылка к тому, что бы определить некую "интерфейсную" сущность.
G>>Она имеет вполне конкретные неправильные решения. И одно из них — ваше.
G>Конкретно, неправильное решение, это вариант R<-S. Для варианта S<-R существуют агрегаты, и такие реализации S и R:S, при которых... и т.д. Ну Вы поняли
Я-то понял.... Вы неправильно понимаете принцип Лисков. Вот и вся проблема. Он не может выполняться для некоторых А. Он обязан выполнятся для всех А, иначе это никакой не принцип Лисков.