квадрат может находиться в произвольном количестве контейнеров и композитных фигур,
при изменении размеров нужно менять экземпляр объекта в каждом контейнере
как это будет выглядеть в коде? сможет квадрат сам подменить себя?
Здравствуйте, Gaperton, Вы писали:
G>Здравствуйте, igna, Вы писали:
I>>Если не ошибаюсь, у тебя все объекты неизменяемые, так?
G>Ну да, в первом примере он сделал методы, которые выводят экземпляр подкласса из этого подкласса константными, по другому никак, это единственное решение, не нарушающее принцип подстановки Лисков. Правильнее было бы вообще их наследованием не связывать, правда.
Почему, если не секрет?
Как ты в языках типа С++ заставишь функцию, работающую с Figure, принимать объекты Rectangle и прочих, если они не связаны отношением наследования (т.е. абсолютно разные типы)?
Здравствуйте, madlax, Вы писали:
M>Baudolino,
M>квадрат может находиться в произвольном количестве контейнеров и композитных фигур, M>при изменении размеров нужно менять экземпляр объекта в каждом контейнере M>как это будет выглядеть в коде? сможет квадрат сам подменить себя?
Совершенно непонятно, что такое "находиться в контейнере", и что такое "изменение размеров".
Если речь идет о квадрате с семантикой value-типа (к которой вы привыкли в геометрии), то никакого "изменения размеров" у него не может быть.
Квадраты-значения ведут себя так же, как целые числа. Давайте перефразируем ваш вопрос:
целое может находиться в произвольном количестве контейнеров и композитных фигур,
при изменении значения нужно менять экземпляр объекта в каждом контейнере
как это будет выглядеть в коде? сможет целое сам подменить себя?
И попробуем представить пример. Каким значением вы собираетесь заменить число "пять"? Что будет с программой, в которой все пятерки превратятся в тройки?
Если речь идет о CAD системе, то никакого value-type поведения у квадратов не будет. Квадрат окажется частным случаем ломаной; никаких чудес с взаимонаследованием от прямоугольников не произойдет, т.к. поведение квадрата как части объектной модели не будет накладывать никаких ограничений ни на углы, ни на равенство сторон, ни даже на их количество. В кадах применяется совсем другая алгебра; там есть примитивы merge и subtract, есть примитив group и так далее. Никакие "геометрические" свойства не будут инвариантами, и наследование не будет иметь никакого смысла.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, Gaperton, Вы писали:
G>>Здравствуйте, igna, Вы писали:
I>>>Если не ошибаюсь, у тебя все объекты неизменяемые, так?
G>>Ну да, в первом примере он сделал методы, которые выводят экземпляр подкласса из этого подкласса константными, по другому никак, это единственное решение, не нарушающее принцип подстановки Лисков. Правильнее было бы вообще их наследованием не связывать, правда.
J>Почему, если не секрет? J>Как ты в языках типа С++ заставишь функцию, работающую с Figure, принимать объекты Rectangle и прочих, если они не связаны отношением наследования (т.е. абсолютно разные типы)?
J>Или все на шаблонах будешь делать?
Надо квадрат с прямоугольником наследованием не связывать. Толку от этого ноль в реальной ситуации, только проблемы. А вот от какого-то абстрактного Figure и то и другое наследовать можно, но ведь об этом в условии задачи ни слова, не так ли?
Здравствуйте, Кодёнок, Вы писали:
Кё>Я ищу примеры классов объектов, которые вызывают трудности при объектном моделировании в современных ЯП типа C++ или C#. В качестве примера, я знаю всего две классические задачи:
Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?). Другая трудность в том, что прямоугольник иногда может являться квадратом, но классические отношения между классами, которые предлагают ЯП (наследование и implicit-conversion) не могут выразить такого отношения.
Кё>2. Комплексное число и вещественное число. Хотя вещественное число является комплексным (наследование), вы не станете наследовать его от комплексного по многим причинам: вам не нужна его реализация (два float в памяти вместо одного), вы вряд ли будете рады тому что sqrt(4) вместо 2.0 вернёт тупл из двух комплексных чисел, и т.п.
Кё>Также буду рад услышать названия языков, которые попытались реализовать более богатый набор отношений, чем даёт классическое понимание объектно-ориентированного проектирования.
Трудно ответить на вопрос, которые выдает с головой ваше непонимание смысла ООП, не в обиду будет сказано. Но я мужественно попробую
Для начала, иерархия классов — это увеличение сложности. Если взять три отдельных класса и три класса, объединяемых в иерархию, то последняя конструкция сложнее. Сопровождать и поддерживать иерархию гораздо сложнее отдельных классов — больше зависимостей и пр... Я думаю это понятно, можно не продолжать.
Но все-таки иерархии существуют. Потому что иногда, при определенных целях, грамотная иерархия позволяет уменьшить сложность.
Далее, иерархия классов — это способ решения задачи. А где у Вас задача-то? Вы задаете вопрос об иерархии и совершенно ничего не говорите о целях. Главный вопрос — зачем? Зачем нужно придумать искусственную конструкцию? Поскольку Вы не определились с целями, то и ответа нет.
Если Вы от _методов_ решения, переместите взгляд на _цели_ (задачи), то Вам станет легче жить. Например, цель может быть такая: унификация хранения. Или — унификация отображения. Или — унификация расчетов и т.д.
Допустим Вы ставите цель: унификация отображения геометрической фигуры.
Тут же Вы понимаете — не нужна Вам никакая иерархия. Все что Вам нужно, это:
interface
{
void draw(TCanvas canvas, RECT rect);
}
Причем это решение вообще не накладывает никаких ограничений на то, что именно рисуется — квадрат, круг или портрет Дориана Грея.
Вот и ответ на Ваш вопрос.
То же рассуждение касается и чисел. Когда Вы пытаетесь неутомимым программистским умом запихнуть в одну конструкцию вещественные и комплексные числа, Вы спросите себя — зачем? Зачем Вам знать сколько там float-ов в вещественном числе? Нет, правда — зачем? Вам беспокоит вопрос унификации хранения разнородных объектов? А почему? Вы хотите их на диск сбрасывать в записи фиксированной длины?
Основная цель ООП: снижение сложности программирования для программиста. Точка. Все остальные задачи, которые любят обсуждать на форумах являются ложными (мнимыми). Сюда относятся вопросы типа "надо ли считать собаку объектом или это набор интерфейсов", "отчего множественное наследование рождает столько проблем и как нам нравится на них натыкаться" и т.д.
Здравствуйте, Krovosos, Вы писали:
K>Трудно ответить на вопрос, которые выдает с головой ваше непонимание смысла ООП, не в обиду будет сказано. Но я мужественно попробую
Ответ на вопрос, которого не было, выдает с головой неясность и запутанность мышления. В моем письме не было вопроса
По существу, иерархия — это не увеличение сложности. Иерархия это система отношений между типами. Отношения между типами нужны, потому что типы бывают взаимозаменяемыми. Иерархия это один из способов реализации подтипов: везде где требуется базовый класс, можно подставить дочерний. В довесок, ОО-языки совмещают это с наследованием реализации, хотя и не всегда, что имеет свои проблемы, некоторые из которых показаны.
K>>Трудно ответить на вопрос, которые выдает с головой ваше непонимание смысла ООП, не в обиду будет сказано. Но я мужественно попробую
Кё>Ответ на вопрос, которого не было, выдает с головой неясность и запутанность мышления. В моем письме не было вопроса
Значит мне показалось
Кё>По существу, иерархия — это не увеличение сложности.
Увеличение. Я же говорю возьмите три независимых класса и три класса, которые наследуют друг от друга. Где будет больше неопределенности в поведении?
Кё>Иерархия это система отношений между типами. Отношения между типами нужны, потому что типы бывают взаимозаменяемыми.
"Взаимозаеменямость" это всего лишь реализация интерфейсов. Иерархия (суть — наследование поведения) отсюда напрямую никак не вытекает.
Кё>Иерархия это один из способов реализации подтипов: везде где требуется базовый класс, можно подставить дочерний. В довесок, ОО-языки совмещают это с наследованием реализации, хотя и не всегда, что имеет свои проблемы, некоторые из которых показаны.
Еще раз говорю: определитесь с целью. Зачем именно нужно Вам подставлять дочерний вместо базового? Почему нельзя обойтись интерфейсами, зачем именно нужен общий базовый класс?
Это иллюзия, что хорошая продуманная иерархия классов придает стройность и упрощает проекты. Все как раз наоборот.
Чем идеальнее Вы развяжете классы и отсечете их друга от друга — тем проще будет жить.