Re[3]: Трудные для ООП иерархии классов
От: Igor Trofimov  
Дата: 21.09.07 05:45
Оценка: 8 (2) +5
D>Однако есть один момент. Когда ООП-ники говорят про преимущества ООП, одним из основных аргументов служит следующий:
D>ОО проектирование легко позволяет моделировать окружающий мир. Видим в нём сотрудников — делаем класс Employee, видим начальника — делаем класс Manager, поскольку начальник is a сотрудник (в окружающем мире так) пользуем наследование.

А вот это как раз и неверно!
Если не ошибаюсь, такую формулировку ("ООП моделирует объекты реального мира") вводит Буч в своей книжке.
А вот умный Бертран Мейер, которого я продолжаю рекомендовать почитать, говорит иначе, примерно так (передаю смысл):

Какая, нах, модель реального мира? Какие объекты из реального мира моделирует компилятор? База данных? Или игра "тетрис"?
Программа реализует некоторую модель вашей предметной области, которая может иметь весьма мало общего с реальным миром.
Процедурный подход реализует модель "тетриса" процедурно. ООП — реализует ту же, по сути, модель, но объектно, что действительно удобно, т.к. конструкции языка ближе к структуре самой модели.


D>Так вот проблемы с квадратом и прямоугольником как раз показывают, что по большому счёту эта простая схема — впендюринг.


Думаю, даже не впендюринг, а реально заблуждение некоторых. Маленькая такая неточность, которая иногда может вылиться в большие проблемы (это вообще свойственно маленьким неточностям).
Re: Трудные для ООП иерархии классов
От: Igor Trofimov  
Дата: 20.09.07 18:22
Оценка: 3 (1) +4
Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?). Другая трудность в том, что прямоугольник иногда может являться квадратом, но классические отношения между классами, которые предлагают ЯП (наследование и implicit-conversion) не могут выразить такого отношения.

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

Рассмотрим, что вам нужно в программе:

1) У любой фигуры есть положение (Location).
2) У фигуры "прямоугольник" задается ширина и высота. Это два независимых параметра, которые можно менять.
3) У фигуры "квадрат" задается размер стороны. Этот параметр можно менять.

Вот исходя из этих исходных данных можно совершенно определенно сказать, что "квадрат" никак не может являться "прямоугольником"!
Потому что у него нет двух независимых параметров "ширина" и "высота".

Откуда вы вообще взяли, что "квадрат всегда является прямоугольником"? Кто вам сказал этот бред?
Вот здесь кроется ошибка!
Вы это взяли из ДРУГОЙ МОДЕЛИ, из геометрии. Но там квадрат и прямоугольник — это СОВСЕМ ДРУГОЕ. Нечто, совсем непохожее, как бы вам не казалось на первый взгляд!
Там вообще нет таких понятий как "менять высоту", например Там это вообще — не объект с параметрами и поведением, а некое геометрическое место точек И с позиции тех свойств, в той модели, да, квадрат, определенно является прямоугольником. Но при чем тут ваша программа?!

Надеюсь, доходчиво объяснил, почему эта иерархия не трудна для ООП
Re[2]: Трудные для ООП иерархии классов
От: Sinclair Россия https://github.com/evilguest/
Дата: 21.09.07 08:15
Оценка: +5
Здравствуйте, Delight, Вы писали:
D>Потому что у него есть и ширина, и высота. По мне так можно унаследовать квадрат от прямоугольника, переопределить сеттеры и при изменении одной стороны автоматически изменять другую.
Ребята, попользуйте поиск. Квадраты с прямоугольниками в ООП обсуждались на этом сайте досконально уже раза три. Все ответы, которые вы можете придумать, уже были даны.
Правильный ответ — такой: при проектировании иерархии не надо думать о свойствах. Думайте о поведении. Если речь идет о CAD или векторном граф.редакторе, у вас 100% не будет классов ни для квадратов, ни для прямоугольников. Если речь идет о системе для решения геометрических задач, то никаких сеттеров ни у кого не будет вообще.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Трудные для ООП иерархии классов
От: deniok Россия  
Дата: 20.09.07 18:38
Оценка: +3 :)
Здравствуйте, Igor Trofimov, Вы писали:

iT>Очень много проблем от того, что интуитивно вы смешиваете ту модель, которая вам нужна в программе с той моделью, которая у вас в голове, от реального мира, от геометрии, и т.п.

iT>Вот про вторую надо забыть

На всякий случай : я полностью согласен с поскипаным объяснением.

Однако есть один момент. Когда ООП-ники говорят про преимущества ООП, одним из основных аргументов служит следующий:

ОО проектирование легко позволяет моделировать окружающий мир. Видим в нём сотрудников — делаем класс Employee, видим начальника — делаем класс Manager, поскольку начальник is a сотрудник (в окружающем мире так) пользуем наследование.

Так вот проблемы с квадратом и прямоугольником как раз показывают, что по большому счёту эта простая схема — впендюринг.
Re[4]: Трудные для ООП иерархии классов
От: mkizub Литва http://symade.tigris.org
Дата: 24.09.07 09:50
Оценка: -3 :)
Здравствуйте, mrozov, Вы писали:

M>DSL — это только один из вариантов развития. Затачивание языка под прикладную область/тип мышления. Было бы неплохо нащупать прорыв


DSL вообще не вариант. Проблема не в создании нового языка, и уж тем более узкоспециализированного. Проблема в эффективном использовании этого языка, а эффективность обеспечивается качественными компиляторами, IDE, отладчиками, библиотеками и людьми которые умеют язык использовать. Создание подобной инфраструктуры стоит десятки, сотни миллионов баксов. Эти деньги можно вложить только в мэйнстрим язык, и то вскладчину, всем миром. В подобный уровень поддержки DSL языка никто вкладываться не будет. А без такой инфраструктуры, хоть DSL и облегчает программирование в конкретной области, он как правило не может превысить эффективности языка общего назначения.

Прорыв известен уже давно — вместо программирования в синтаксических конструкциях надо программировать в семантических значениях. Самым разрекламированным в этом направлении является Intentional Programming (особо этому помогло то, что про его детали реализации никто ничего не знает, и все надеются на лучшее). Такой подход позволит легко определять онтологии для предметных областей (функции DSL), адаптировать имеющийся язык к конкретной задаче (расширение языка), легко адаптироваться к усложняющемуся железу и т.п.

Пока этот подход был не очень конкурентоспособен — поскольку предъявляет достаточно большие требования к сложности софта и железа разработчика. Так же как кислородное дыхание было невыгодно, по сравнению с анаэробным, до определённого уровня насыщенности воды/атмосферы кислородом.

Фактически, нынешние компьютеры разработчиков уже предоставляют достаточную мощность для семантического программирования, но они не могут пробиться в массы всё по тем-же причинам — экологическая ниша уже занята. Но ниши, в которых нынешний мэйнстрим не справляется — существуют. В этих нишках и прозябают нынешние DSLи. В них семантическое программирование и начнёт своё становление. А лет через 10-15, когда закончится действие закона Мура, и изготовители железа перейдут от погони за количеством (мегагерц, транзисторов, ядер) к погоне за качеством (сложностью, адаптивностью и т.п.) — нынейшний мэйнстрим не сможет предложить никаких вариантов, и будет почти полностью вытеснен.
SOP & SymADE: http://symade.tigris.org , блог http://mkizub.livejournal.com
Re: Трудные для ООП иерархии классов
От: deniok Россия  
Дата: 20.09.07 14:24
Оценка: 16 (3)
Здравствуйте, Кодёнок, Вы писали:

[]

У Олега Киселёва есть на эту тему замечательные статья:

Does OOP really separate interface from implementation?

и её продолжение:

Subclassing errors, OOP style and practically checkable rules to prevent them

ЗЫ: в мире функционального программирования понимание человеком тонкостей систем типов измеряют в миллиОлегах.
Re[3]: Трудные для ООП иерархии классов
От: Sinclair Россия https://github.com/evilguest/
Дата: 21.09.07 03:06
Оценка: +3
Здравствуйте, deniok, Вы писали:

D>Однако есть один момент. Когда ООП-ники говорят про преимущества ООП, одним из основных аргументов служит следующий:


D>ОО проектирование легко позволяет моделировать окружающий мир. Видим в нём сотрудников — делаем класс Employee, видим начальника — делаем класс Manager, поскольку начальник is a сотрудник (в окружающем мире так) пользуем наследование.


Прикольно. Самое смешное, что я не могу вспомнить такого аргумента. Ну то есть я знаю, что это наверняка из-за того, что я читал мало книжек. Но вообще-то, основной аргумент за ООП никак не связан с моделированием реального мира. Основной аргумент — это борьба со связностью программы, благодаря инкапсуляции и полиморфизму. Вышеописанный подход — это какое-то неправильное ООП. В реальном программировании так никогда не делается. Где вы видели отнаследованного от сотрудника начальника?
В нормальном ООП, скорее всего, и сотрудник и начальник будут просто строчками в базе данных, при этом никто ни от кого не будет наследоваться, а будет связь между человеком и позицией, причем один-ко-многим, и будет интерфейс IHumanResources, отвечающий за назначение должностей и прочие простые штуки. И будет куча реализаций этого интерфейса — поверх XML файла для микроконтор, и поверх MS SQL Server Enterprize Edition для корпораций. И будет отнаследованный от него интерфейс типа IAdvancedHumanResources, в котором помимо базовой функциональности будет масса возможностей вроде поддержки организации проектных команд, планирования аттестаций и учета вакансий.
Очевидно, что ни один из этих классов не имеет никаких аналогов в реальном мире. Тем не менее, преимущества ООП по сравнению с, к примеру, процедурным программированием, также очевидны.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[2]: Трудные для ООП иерархии классов
От: igna Россия  
Дата: 24.09.07 08:48
Оценка: +1 :))
Здравствуйте, jazzer, Вы писали:

J>Эта проблема, вообще-то, никакого отношения к ООП не имеет.


Согласен. IMHO большинство проблем не имеет отношения к ООП, и наоборот ООП не имеет отношения к большинству проблем. Имею ввиду именно проблемы программирования, а не проблемы вообще, так как к счастью никакой философской школы из ООП вроде не возникло, так что ОООПисты хоть непрограммистам мозги не мучают. Менеджерам разве еще...
Re: Трудные для ООП иерархии классов
От: Krovosos  
Дата: 11.10.07 18:44
Оценка: +3
Здравствуйте, Кодёнок, Вы писали:

Кё>Я ищу примеры классов объектов, которые вызывают трудности при объектном моделировании в современных ЯП типа C++ или C#. В качестве примера, я знаю всего две классические задачи:


Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?). Другая трудность в том, что прямоугольник иногда может являться квадратом, но классические отношения между классами, которые предлагают ЯП (наследование и implicit-conversion) не могут выразить такого отношения.


Кё>2. Комплексное число и вещественное число. Хотя вещественное число является комплексным (наследование), вы не станете наследовать его от комплексного по многим причинам: вам не нужна его реализация (два float в памяти вместо одного), вы вряд ли будете рады тому что sqrt(4) вместо 2.0 вернёт тупл из двух комплексных чисел, и т.п.


Кё>Также буду рад услышать названия языков, которые попытались реализовать более богатый набор отношений, чем даёт классическое понимание объектно-ориентированного проектирования.


Трудно ответить на вопрос, которые выдает с головой ваше непонимание смысла ООП, не в обиду будет сказано. Но я мужественно попробую


Для начала, иерархия классов — это увеличение сложности. Если взять три отдельных класса и три класса, объединяемых в иерархию, то последняя конструкция сложнее. Сопровождать и поддерживать иерархию гораздо сложнее отдельных классов — больше зависимостей и пр... Я думаю это понятно, можно не продолжать.

Но все-таки иерархии существуют. Потому что иногда, при определенных целях, грамотная иерархия позволяет уменьшить сложность.

Далее, иерархия классов — это способ решения задачи. А где у Вас задача-то? Вы задаете вопрос об иерархии и совершенно ничего не говорите о целях. Главный вопрос — зачем? Зачем нужно придумать искусственную конструкцию? Поскольку Вы не определились с целями, то и ответа нет.

Если Вы от _методов_ решения, переместите взгляд на _цели_ (задачи), то Вам станет легче жить. Например, цель может быть такая: унификация хранения. Или — унификация отображения. Или — унификация расчетов и т.д.

Допустим Вы ставите цель: унификация отображения геометрической фигуры.

Тут же Вы понимаете — не нужна Вам никакая иерархия. Все что Вам нужно, это:

interface
{
void draw(TCanvas canvas, RECT rect);
}

Причем это решение вообще не накладывает никаких ограничений на то, что именно рисуется — квадрат, круг или портрет Дориана Грея.

Вот и ответ на Ваш вопрос.

То же рассуждение касается и чисел. Когда Вы пытаетесь неутомимым программистским умом запихнуть в одну конструкцию вещественные и комплексные числа, Вы спросите себя — зачем? Зачем Вам знать сколько там float-ов в вещественном числе? Нет, правда — зачем? Вам беспокоит вопрос унификации хранения разнородных объектов? А почему? Вы хотите их на диск сбрасывать в записи фиксированной длины?

Основная цель ООП: снижение сложности программирования для программиста. Точка. Все остальные задачи, которые любят обсуждать на форумах являются ложными (мнимыми). Сюда относятся вопросы типа "надо ли считать собаку объектом или это набор интерфейсов", "отчего множественное наследование рождает столько проблем и как нам нравится на них натыкаться" и т.д.

Re: Трудные для ООП иерархии классов
От: Трурль  
Дата: 21.09.07 06:58
Оценка: 11 (2)
Здравствуйте, Кодёнок, Вы писали:

Кё>Я ищу примеры классов объектов, которые вызывают трудности при объектном моделировании в современных ЯП типа C++ или C#.


Мне кажется, трудности во многом вызываются использованием единого механизма наследования для выражения совершнно разных отношений:
  • тип — подтип;
  • структура — расширение cтруктуры;
  • интерфейс — реализация;
  • интерфейс — расширеный интерфейс;
  • используемый интерфейс — реализация;
  • реализация — точно такая же, но с перламутровыми пуговицами;
  • ...
  • Re: Трудные для ООП иерархии классов
    От: mrozov  
    Дата: 21.09.07 13:56
    Оценка: 3 (1) +1
    Забавное обсуждение
    Автор привел пару примеров задач, решение которых в рамках традиционного ООП является затруднительным, и попросил подкинуть еще (т.е. добавить убедительности, по сути).
    А ему в ответ все дружно начали объяснять, как эти примеры нужно переписать, чтобы затруднений не было (т.е. решать прямо обратную задачу).

    Понятно, что можно все красиво переделать, оставаясь в рамках ООП. Или функциональщины. Или процедурного программирования. Понятно, что любой алгоритм можно переписать на ассемблере или на Smalltalk-е, было бы желание.

    Но все это ни в малейшей степени не означает, что приведенные примеры не являются затруднительными для решения. Идеальный язык не будет навязывать свою парадигму мышления, он будет логично встраиваться в систему взглядов эксперта предметной области. Я так понимаю, что речь именно об этом.
    Re[2]: Трудные для ООП иерархии классов
    От: Андрей Коростелев Голландия http://www.korostelev.net/
    Дата: 23.09.07 09:14
    Оценка: 3 (1) +1
    Здравствуйте, Кодт, Вы писали:

    К>>ужно определиться с тем, что именно означает иерархия структур в каждом случае: это специализация (субклассирование) или расширение (наследование).

    К>К специализации применим LSP, к расширению — очевидно, нет.

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

    Наследование с целью расширения наряду со специализацией и спецификацией (поледнее является частным случаем специализации, например, наследование интерфейса) входит в список "правильных" форм наследования для которых выполняется LSP, то есть для которых подклассы всегда являются подтипами.

    К>В Блоге Труъ Программиста в августе была серия статей на тему.

    -- Андрей
    Трудные для ООП иерархии классов
    От: Кодёнок  
    Дата: 20.09.07 11:17
    Оценка: 2 (2)
    Я ищу примеры классов объектов, которые вызывают трудности при объектном моделировании в современных ЯП типа C++ или C#. В качестве примера, я знаю всего две классические задачи:

    1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?). Другая трудность в том, что прямоугольник иногда может являться квадратом, но классические отношения между классами, которые предлагают ЯП (наследование и implicit-conversion) не могут выразить такого отношения.

    2. Комплексное число и вещественное число. Хотя вещественное число является комплексным (наследование), вы не станете наследовать его от комплексного по многим причинам: вам не нужна его реализация (два float в памяти вместо одного), вы вряд ли будете рады тому что sqrt(4) вместо 2.0 вернёт тупл из двух комплексных чисел, и т.п.

    Также буду рад услышать названия языков, которые попытались реализовать более богатый набор отношений, чем даёт классическое понимание объектно-ориентированного проектирования.
    Re: Трудные для ООП иерархии классов
    От: Кодт Россия  
    Дата: 21.09.07 10:03
    Оценка: 6 (1)
    Здравствуйте, Кодёнок, Вы писали:

    Кё>Я ищу примеры классов объектов, которые вызывают трудности при объектном моделировании в современных ЯП типа C++ или C#. В качестве примера, я знаю всего две классические задачи:


    Нужно определиться с тем, что именно означает иерархия структур в каждом случае: это специализация (субклассирование) или расширение (наследование).
    К специализации применим LSP, к расширению — очевидно, нет.

    Благодаря тому, что в обычных языках наследование как технический инструмент позволяет и специализировать, и расширять класс (перекрытие/перегрузка интерфейсных функций; надстройка layout'а и изменение семантики на корню), возникает прекрасная почва для путаницы в сознании.

    В Блоге Труъ Программиста в августе была серия статей на тему.

    Кё>Также буду рад услышать названия языков, которые попытались реализовать более богатый набор отношений, чем даёт классическое понимание объектно-ориентированного проектирования.


    Haskell и O'Haskell. В последнем — вопросам классовой борьбы уделяется много внимания.
    ... << RSDN@Home 1.2.0 alpha rev. 655>>
    Перекуём баги на фичи!
    Re: Трудные для ООП иерархии классов
    От: Cephalopod  
    Дата: 20.09.07 11:49
    Оценка: 3 (1)
    Здравствуйте, Кодёнок, Вы писали:

    Кё>Также буду рад услышать названия языков, которые попытались реализовать более богатый набор отношений, чем даёт классическое понимание объектно-ориентированного проектирования.


    Coq. HOL. Axiom.

    P.S. OOP stinks
    Re[2]: Трудные для ООП иерархии классов
    От: COFF  
    Дата: 21.09.07 13:48
    Оценка: 3 (1)
    Кё>>... квадрат всегда является прямоугольником ...

    I>Изменяемый квадрат не всегда является изменяемым прямоугольником. А в программировании в отличии от математики квадраты и прямоугольники как правило изменяемы.


    Кстати, интересный факт из геометрии — квадрат, является не только прямоугольником, но и ромбом, параллелограммом и четырехугольником, а также возможно и трапецией (здесь я не уверен). Так что, судя по всему, объектная иерархия может существенно запутаться
    Re[2]: Трудные для ООП иерархии классов
    От: Курилка Россия http://kirya.narod.ru/
    Дата: 20.09.07 11:52
    Оценка: 2 (1)
    Здравствуйте, Cephalopod, Вы писали:

    C>P.S. OOP stinks


    А вот статейка на эту тему
    Re[5]: Трудные для ООП иерархии классов
    От: _DAle_ Беларусь  
    Дата: 23.09.07 13:40
    Оценка: 1 (1)
    Здравствуйте, nikov, Вы писали:

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


    I>>P.S. Параллелограмм это трапеция


    N>Это неверно. Смотреть любой учебник геометрии или здесь.


    Как категорично. Предлагаю прочитать первый абзац в английской версии статьи.

    P.S. Я обычно статьи (на тематику, не связанную с Россией) из русскоязычной википедии даже не читаю, когда мне ссылки дают на нее, переключаюсь на соответствующую англоязычную статью сразу.
    ... << RSDN@Home 1.1.4 beta 7 rev. 447>>
    Re: Трудные для ООП иерархии классов
    От: COFF  
    Дата: 20.09.07 15:13
    Оценка: +1
    Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?). Другая трудность в том, что прямоугольник иногда может являться квадратом, но классические отношения между классами, которые предлагают ЯП (наследование и implicit-conversion) не могут выразить такого отношения.

    Кё>2. Комплексное число и вещественное число. Хотя вещественное число является комплексным (наследование), вы не станете наследовать его от комплексного по многим причинам: вам не нужна его реализация (два float в памяти вместо одного), вы вряд ли будете рады тому что sqrt(4) вместо 2.0 вернёт тупл из двух комплексных чисел, и т.п.


    Мне кажется, что иерархия объектов — это не что-то объективно существующее, а всего лишь модель, которая позволяет нам более-менее адекватно описывать предметную область. Соответственно и примеры, данные выше, надо рассматривать в контексте области применения.
    Вот предположим, что у нас есть прямоугольник, который может произвольным образом менять свои размеры, соответственно, максимум, что мы можем тут сделать — это ввести признак isSquare. Если же объекты у нас создаются один раз, а потом рисуются и метод рисования квадрата отличается от метода рисования прямоугольника (эффективнее), то класс квадрата и класс прямоугольника могут быть связаны только через общий класс-предок (например, фигура), и выбирать, объект какого класса должен быть создан должна соответствующая фабрика. Ну и так далее...
    С комплексными числами то же самое. Подумайте, зачем они вам нужны и принимайте решение, исходя из этого.
    Re[3]: Трудные для ООП иерархии классов
    От: Delight  
    Дата: 21.09.07 08:25
    Оценка: -1
    Здравствуйте, konsoletyper, Вы писали:

    D>>Потому что у него есть и ширина, и высота. По мне так можно унаследовать квадрат от прямоугольника, переопределить сеттеры и при изменении одной стороны автоматически изменять другую.


    K>Наследование класса — это сахар. Да и определение класса — тоже сахар; по сути происходит описание интерфейса и его же реализация. Вот если иммутабельные Rectangle и Square реализуют интерфейс IRectange, то проблем не возникает. А зачем нужны мутабельные Rectangle и Square?


    Если нужны мутабельные, то нужно делать мутабельные. Впрочем у меня эта боян-проблема-в-себе вызывает довольно вялый интерес. На флейм не пойду.
    ... << RSDN@Home 1.2.0 alpha rev. 726>>
    Re: Трудные для ООП иерархии классов
    От: konsoletyper Россия https://github.com/konsoletyper
    Дата: 21.09.07 08:25
    Оценка: +1
    Здравствуйте, Кодёнок, Вы писали:

    Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?). Другая трудность в том, что прямоугольник иногда может являться квадратом, но классические отношения между классами, которые предлагают ЯП (наследование и implicit-conversion) не могут выразить такого отношения.


    Последнее отношение выполняется не всегда. Есть верное утверждение "квадрат? x => прямоугольник? x", т.е. любой квадрат можно представить как прямоугольник, но утверждение "прямоугольник? x => квадрат? x" в общем случае неверно, соответственно, никто по рукам бить не будет, если мы нарушим LSP. Так что можно обойтись явным приведением прямоугольника к квадрату, с выбросом исключения при необходимости.

    Кё>2. Комплексное число и вещественное число. Хотя вещественное число является комплексным (наследование), вы не станете наследовать его от комплексного по многим причинам: вам не нужна его реализация (два float в памяти вместо одного), вы вряд ли будете рады тому что sqrt(4) вместо 2.0 вернёт тупл из двух комплексных чисел, и т.п.


    А кто сказал, что нужно наследовать реализацию? С интерфейсами не возникает никаких проблем. В частности, sqrt для float и sqrt для complex — это, вообще-то, математически разные вещи, просто символ радикала является полиморфным (например, в той же математики делается различие между Ln и ln). Так что тут надо либо давать другое имя, либо делать explicit-реализацию метода IComplex.Sqrt, либо юзать язык с перегрузкой типов по возвращаемому значению.

    Зато есть другая вещь, которую вот так просто в терминах "классового" ООП не выразишь. Например, поле комплексных чисел является алгебраически замкнутым, а поле действительных — нет. Или ещё пример: Z является кольцом, а R — полем. И что тут делать? Хочу заметить, что подобные вещи вообще в терминах "классовых" ООЯ неудобно записывать. Гораздо лучше в терминах type classes из Haskell. Или на худой конец, в динамике. Если выражать в статике, то получим множественные runtime проверки типов, что по сути та же динамака.

    Кё>Также буду рад услышать названия языков, которые попытались реализовать более богатый набор отношений, чем даёт классическое понимание объектно-ориентированного проектирования.


    Smalltalk, Self вроде бы теоретически больше позволяют, чем "классовые" ООЯ, хотя у них есть свои проблемы.
    ... << RSDN@Home 1.2.0 alpha rev. 710>>
    Re[3]: Трудные для ООП иерархии классов
    От: lomeo Россия http://lomeo.livejournal.com/
    Дата: 21.09.07 09:45
    Оценка: +1
    Здравствуйте, Кодёнок, Вы писали:

    Кё>Это с какой стати? Вообще-то я моделирую предметную область с помощью средств языка программирования. С какого перепуга я должен забыть о предметной области?


    Насколько я понял, Igor Trofimov говорит о том, что квадрат из геометрии (реального мира) не является объектом предметной области. Объект предметной области — квадрат с изменяющейся стороной.
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[3]: Трудные для ООП иерархии классов
    От: igna Россия  
    Дата: 23.09.07 08:13
    Оценка: +1
    Здравствуйте, COFF, Вы писали:

    COF>Кстати, интересный факт из геометрии — квадрат, является не только прямоугольником, но и ромбом, параллелограммом и четырехугольником, а также возможно и трапецией (здесь я не уверен). Так что, судя по всему, объектная иерархия может существенно запутаться


    Для этого есть множественное наследование. Но если вдруг в дополнение ко всем этим фигурам позже захочется поиметь еще и многоугольник, придется менять иерархию.

    P.S. Параллелограмм это трапеция, а трапеция это четырехугольник. А еще и дельтоид есть.
    Re: Трудные для ООП иерархии классов
    От: elmal  
    Дата: 20.09.07 11:40
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:

    Кё>Я ищу примеры классов объектов, которые вызывают трудности при объектном моделировании в современных ЯП типа C++ или C#. В качестве примера, я знаю всего две классические задачи:


    ИМХО и в первом и во втором случае имеем неправильную иерархию. Уже писал когда-то по поводу квадрата здесь
    Автор: elmal
    Дата: 07.03.07


    Комплексные и обычные числа — тоже самое:
    Наследоваться нужно от класса 'число' (если уж вообще возникла необходимость в наследовании). Далее их можно разделить на всякие — натуральные, мнимые, действительными, положительные и т.д. Соответственно 'обычные' чиcла являются действительными, а комплексные — мнимыми.

    Все описанные тобой проблемы ИМХО из-за того, что неправильно иерархии строят. Если уж строить, то строить по аналогии со школьным учебником, а там иерархии гораздо сложнее, чем в твоем примере. И тогда построить непротиворечивую эффективную иерархию не проблема, только несколько более громоздкой она получится.
    Re[2]: Трудные для ООП иерархии классов
    От: Кодёнок  
    Дата: 20.09.07 12:23
    Оценка:
    Здравствуйте, elmal, Вы писали:

    E>Наследоваться нужно от класса 'число' (если уж вообще возникла необходимость в наследовании). Далее их можно разделить на всякие — натуральные, мнимые, действительными, положительные и т.д. Соответственно 'обычные' чиcла являются действительными, а комплексные — мнимыми.


    То есть предлагаешь иерархию использовать только для классификации их всех как "чисел", а автоматическую совместимость между ними реализовать через implicit conversion?

    А как решить проблему sqrt?
    Re[3]: Трудные для ООП иерархии классов
    От: Кодёнок  
    Дата: 20.09.07 12:38
    Оценка:
    Здравствуйте, Курилка, Вы писали:

    C>>P.S. OOP stinks

    К>А вот статейка на эту тему

    Что-то не очень убедительная статья. Есть заявления в стиле "так вот, на самом деле это плохо и должно быть наоборот", но нет аргументов, почему. Безапелляционные утверждения — не лучший способ убедить.
    Re[2]: Трудные для ООП иерархии классов
    От: Кодёнок  
    Дата: 20.09.07 12:41
    Оценка:
    Здравствуйте, Cephalopod, Вы писали:

    Кё>>Также буду рад услышать названия языков, которые попытались реализовать более богатый набор отношений, чем даёт классическое понимание объектно-ориентированного проектирования.


    C> Coq. HOL. Axiom.


    Спасибо, я посмотрю.
    Re[4]: Трудные для ООП иерархии классов
    От: Курилка Россия http://kirya.narod.ru/
    Дата: 20.09.07 12:48
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:

    Кё>Здравствуйте, Курилка, Вы писали:


    C>>>P.S. OOP stinks

    К>>А вот статейка на эту тему

    Кё>Что-то не очень убедительная статья. Есть заявления в стиле "так вот, на самом деле это плохо и должно быть наоборот", но нет аргументов, почему. Безапелляционные утверждения — не лучший способ убедить.


    Почему безапелляционные?
    Возьмём 4-й пункт "У объектов есть private состояние" — с самим утверждением не будешь спорить, надеюсь?
    Джо говорит, что состояние — одна из проблем, состояние увеличивает зависимости, уменьшает расспараллеливаемость и т.д.
    "Обычные" языки пытаются "спрятать" состояние (с помощью модификаторов и т.п.), тогда как в декларативных функциональных есть подаваемые данные на вход и результат на выходе.

    И что здесь тебе показалось "безапелляционным"?
    Скорее твоё утверждение таковым назвать следует
    Re[3]: Трудные для ООП иерархии классов
    От: elmal  
    Дата: 20.09.07 12:58
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:

    Кё>То есть предлагаешь иерархию использовать только для классификации их всех как "чисел", а автоматическую совместимость между ними реализовать через implicit conversion?

    В общем да, а вот в деталях может оказаться что и нет . От деталей реализации все зависит.

    Кё>А как решить проблему sqrt?

    А какая проблема с sqrt? sqrt(Number number) и должен возвращать набор чисел. sqrt(4) = 2 и -2 насколько я помню. И собственно когда мы его будем возвращать — эти числа должно быть наиболее адекватного типа. Ну а sqrt(-1) должен возвратить комплексное число, вроде оно наже одно (блин, уже школьную программу забываю — ужас). Если для корня определенного числа возвратится несколько значений разных типов (например одно комплексное, другое действительное), а мне нужен допустим только действительные — я могу лишние отбросить. Я бы например сделал, чтобы sqrt возвращал объект класса 'Корни'. И у этого класса можно сделать методы фильтрации по содержимому — возвратить только положительные, возвратить только действительные и т.д, возвратить как список, как массив, получить итератьр и т.д.
    Re: Трудные для ООП иерархии классов
    От: no4  
    Дата: 20.09.07 13:35
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:


    Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?).


    Почему прямоугольник должен ХРАНИТЬ ширину и высоту?
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re: Трудные для ООП иерархии классов
    От: no4  
    Дата: 20.09.07 13:35
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:


    Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?).


    Почему прямоугольник должен ХРАНИТЬ ширину и высоту?
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re: Трудные для ООП иерархии классов
    От: mkizub Литва http://symade.tigris.org
    Дата: 20.09.07 20:26
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:

    Кё>Я ищу примеры классов объектов, которые вызывают трудности при объектном моделировании в современных ЯП типа C++ или C#. В качестве примера, я знаю всего две классические задачи:


    Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?). Другая трудность в том, что прямоугольник иногда может являться квадратом, но классические отношения между классами, которые предлагают ЯП (наследование и implicit-conversion) не могут выразить такого отношения.


    Кё>2. Комплексное число и вещественное число. Хотя вещественное число является комплексным (наследование), вы не станете наследовать его от комплексного по многим причинам: вам не нужна его реализация (два float в памяти вместо одного), вы вряд ли будете рады тому что sqrt(4) вместо 2.0 вернёт тупл из двух комплексных чисел, и т.п.


    3. List<String> и List<Object>.

    Вообще вышеприведённые примеры показывают трудности объектного моделирования как такового, а не просто в современных языках.

    Кё>Также буду рад услышать названия языков, которые попытались реализовать более богатый набор отношений, чем даёт классическое понимание объектно-ориентированного проектирования.


    А какие ещё отношения ты знаешь?

    Идея наследования — это идея расширения (или сужения, в зависимости от ко- или контр-вариантного наследования) интерфейса, сиречь операций которые можно произвести с данным объектом. Какое ещё действие по отношению к интерфейсу ты можешь себе вообразить (кроме операции добавить/убавить набор операций)? Перетасовать их?
    SOP & SymADE: http://symade.tigris.org , блог http://mkizub.livejournal.com
    Re[2]: Трудные для ООП иерархии классов
    От: deniok Россия  
    Дата: 20.09.07 21:33
    Оценка:
    Здравствуйте, mkizub, Вы писали:

    Кё>>Также буду рад услышать названия языков, которые попытались реализовать более богатый набор отношений, чем даёт классическое понимание объектно-ориентированного проектирования.


    M>А какие ещё отношения ты знаешь?


    M>Идея наследования — это идея расширения (или сужения, в зависимости от ко- или контр-вариантного наследования) интерфейса, сиречь операций которые можно произвести с данным объектом. Какое ещё действие по отношению к интерфейсу ты можешь себе вообразить (кроме операции добавить/убавить набор операций)? Перетасовать их?


    Ну в Haskell есть Multi-parameter type classes:

    -- Интерфейс, задающий отношение изоморфизма между типами
    class Iso a b where
     iso :: a -> b
     osi :: b -> a
    
    -- Пример реализации
    instance Iso a a where
     iso = id
     osi = id


    Фишка в том, что интерфейс выставляется не одним типом, а двумя. VTBL приклеивается не к "объекту", а к методам интерфейса.
    Re[2]: Трудные для ООП иерархии классов
    От: Кодёнок  
    Дата: 21.09.07 06:46
    Оценка:
    Здравствуйте, Igor Trofimov, Вы писали:

    iT>Очень много проблем от того, что интуитивно вы смешиваете ту модель, которая вам нужна в программе с той моделью, которая у вас в голове, от реального мира, от геометрии, и т.п.

    iT>Вот про вторую надо забыть

    Это с какой стати? Вообще-то я моделирую предметную область с помощью средств языка программирования. С какого перепуга я должен забыть о предметной области?
    Re: Трудные для ООП иерархии классов
    От: Sm0ke Россия ksi
    Дата: 21.09.07 07:17
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:

    Кё>Я ищу примеры классов объектов, которые вызывают трудности при объектном моделировании в современных ЯП типа C++ или C#. В качестве примера, я знаю всего две классические задачи:


    Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?). Другая трудность в том, что прямоугольник иногда может являться квадратом, но классические отношения между классами, которые предлагают ЯП (наследование и implicit-conversion) не могут выразить такого отношения.


    Хотя квадрат и является частным случаем прямоугольника, это не значит, что выгодно его наследовать от прямоугльника.
    Скорее наоборот. Square : Figure { width }; Rectangle : Figure { width, height }; Figure { location, rotation, scale };
    Тут замечаем, что у фигур есть общие поля. Теперь мы можем:

    либо (1) завести для них общий базовый класс with_width { width };
    И тогда Square : Figure, with_width {}; Rectangle : Figure, with_width { height };

    либо (2) отнаследовать прямоугольник от квадрата на прямую Square : Figure { width }; Rectangle : Figure, Square { height };


    Но эти решения не всегда эффективны. В случае графического редактора может быть выгоднее другое.
    У фигур есть параметры. Параметры бывают разных типов, но у всех у них есть имя.
    Кроме того фигуры бывают разных типов. Для типов заводим базовый абстрактный класс Prototype.
    Для сериализации картинки, у типов фигур должны быть имена.

    // параметры
    interface IParam
    {};
    
    struct text_param : IParam
    {};
    
    struct number_param : IParam
    {};
    
    // ПараметрЫ. указатель на список параметров ( на хэш )
    typedef map<string, IParam *> * Params;
    
    // фигура (не абстрактный класс!)
    struct Figure
    {
     Prototype * htype;
     Params hparams;
    };
    
    Figure::constructor(Prototype * hnew_type)
    {
      htype= hnew_type;
      hparams= htype->get_default_params();
    }
    
    Figure::draw()
    {
     htype->draw(this);
    }
    
    Figure::serialize(Archive & ar)
    {
      // сериализим имя типа фигуры
      // сериализим список параметров
    }
    
    // прототипы фигур
    struct Prototype abstract
    {
      virtual draw(Figure *) abstract;
      virtual Params get_default_params() abstract;
      virtual string get_name() abstract;
    };
    
    // прототип прямоугольника
    struct type_rect : Prototype
    {
      draw(Figure * hf)
      { /*рисуем прямоугольник*/ }
    
      // другие методы
    };
    
    // тут нужны другие типы фигур ...
    
    // картинка
    struct Picture
    {
      // тут список фигур
      // методы:
      draw(); // рисуем фигуры
      serialize(...); // сериализим фигуры
      add_figure(...);
      del_figure(...);
      // и т.д.
    };


    Квадрат имеет один параметр "сторона" ("side");
    У прямоугольника "width", "height";
    У круга "radius";

    Фигура в этой схеме имеет указатели на тип и на хэш параметров для того, чтобы можно было
    конвертировать одну фигуру в другую. К примеру квадрат преобразовать в прямоугольник.

    Тут не фигура сама себя рисует. За действия над фигурами отвечают их прототипы.
    Таким образом типы фигур не hard-coded, а могут загружаться из библиотек типов.
    т.е. Тип фигуры можно тоже сериализовать.
    Re: Трудные для ООП иерархии классов
    От: Delight  
    Дата: 21.09.07 07:52
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:

    Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?).


    Потому что у него есть и ширина, и высота. По мне так можно унаследовать квадрат от прямоугольника, переопределить сеттеры и при изменении одной стороны автоматически изменять другую.
    ... << RSDN@Home 1.2.0 alpha rev. 726>>
    Re[2]: Трудные для ООП иерархии классов
    От: konsoletyper Россия https://github.com/konsoletyper
    Дата: 21.09.07 07:53
    Оценка:
    Здравствуйте, Sm0ke, Вы писали:

    [skip]

    Изобретаем Self?
    ... << RSDN@Home 1.2.0 alpha rev. 710>>
    Re[2]: Трудные для ООП иерархии классов
    От: konsoletyper Россия https://github.com/konsoletyper
    Дата: 21.09.07 07:58
    Оценка:
    Здравствуйте, Delight, Вы писали:

    D>Потому что у него есть и ширина, и высота. По мне так можно унаследовать квадрат от прямоугольника, переопределить сеттеры и при изменении одной стороны автоматически изменять другую.


    Наследование класса — это сахар. Да и определение класса — тоже сахар; по сути происходит описание интерфейса и его же реализация. Вот если иммутабельные Rectangle и Square реализуют интерфейс IRectange, то проблем не возникает. А зачем нужны мутабельные Rectangle и Square?
    ... << RSDN@Home 1.2.0 alpha rev. 710>>
    Re: Трудные для ООП иерархии классов
    От: Кирилл Лебедев Россия http://askofen.blogspot.com/
    Дата: 21.09.07 08:04
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:

    Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами.

    Для решения какого класса задач нужна такая иерархия?

    Кё>2. Комплексное число и вещественное число.

    Опять-таки: для решения какого класса задач нужна такая иерархия?

    Кё>Также буду рад услышать названия языков, которые попытались реализовать более богатый набор отношений, чем даёт классическое понимание объектно-ориентированного проектирования.

    Предположим, такой язык нашелся. Ваши дальнейшие действия? Чем это Вам поможет при решении конкретных задач?
    С уважением,
    Кирилл Лебедев
    Software Design blog — http://askofen.blogspot.ru/
    Re[2]: Трудные для ООП иерархии классов
    От: Кодёнок  
    Дата: 21.09.07 08:26
    Оценка:
    Здравствуйте, mkizub, Вы писали:

    M>А какие ещё отношения ты знаешь?


    Например то, что в некоторых языках реализовано как трейты (классы типов):

    trait Addable[ThisType] { def +(ThisType other) }

    Позволяет классифицировать как Addable любой тип, в том числе будущий или не подозревающий о существовании Addable. В классическом понимании ООП ты должен построить иерархию сразу, унаследовав всё что нужно от Addable. Если ты берешь стороннюю библиотеку (типичная ситуация при компонентной разработке), её иерархия не может включать твой класс Addable, и таким образом ты имеешь классы, про которые невооруженным взглядом видно что они Addable, но средства языка вроде C# не позволят тебе работать с ними, там, где требуется Addable.



    Или отношение, которое сейчас принято реализовать паттерном прокси. Например, если есть некий IString, и есть классы CString и std::string, которые очевидно могут являться IString, но тот же C++ не позволит тебе добавить еще один интерфейс к уже готовым классам. А в идеальном варианте я бы дописал что-то вроде
    implementation IString for std::string {
    char GetChatAt(int i) { return at(i); }
    }
    Re[3]: Трудные для ООП иерархии классов
    От: mkizub Литва http://symade.tigris.org
    Дата: 21.09.07 08:56
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:

    M>>А какие ещё отношения ты знаешь?


    Кё>Например то, что в некоторых языках реализовано как трейты (классы типов):


    Кё>Или отношение, которое сейчас принято реализовать паттерном прокси.


    Угу. А ещё есть возможность динамически добавлять методы и поля (Python и прочие динамические языки), динамически менять супер-класс (наследование делегированием сообщений). Есть ещё возможность автоматического приведения типов (вроде view в Scala, или просто преобразования int->float в С).
    Но они никак не помогут решить проблему Квадрат-Прямоугольник или Complex-Float-Integer. Первая — просто неправильно построенное наследование, и Квадрат с Прямоугольником должны, скорее, унаследоваться от Фигура (как и Треугольник, Многоугольник, Круг и пр.) — так же как это сделано для byte, int, long, float, double в процедурных языках — они независимы, а не образуют иерархию. А с набором независимых типов есть проблема, заключающаяся в необходимости их знать все заранее. Если ты добавишь к числам complex — то отгребёшь по самое нехочу. А потом ещё можно добавить BigInteger/BigFloat, с неограниченным количеством бит. А если complex и BigFloat добавлены независимо, отдельно друг от друга? Ведь надо-бы иметь BigComplex, а иначе вся система рушится — ведь чему будет равен результат умножения BigFloat * complex?

    При фиксированной задаче мы можем знать набор требований, и можем выбрать иерархию Квадрат->Прямоугольник или Прямоугольник->Квадрат или Фигура->Прямоугольник|Квадрат — в зависимости от той модели, которую нам надо реализовать. Но эта модель будет всегда ограничена. А неограниченная (универсальная) модель автоматически приводит к проблеме несовместимости расширений (как complex*BigFloat).

    И это не проблема ООП. В функциональщине те-же проблемы. Так называемая Expression Problem. Вот в Scala её Мартин Одерски предлагает решать как здесь. По моему, очень коряво. Но альтернативные решения не лучше
    SOP & SymADE: http://symade.tigris.org , блог http://mkizub.livejournal.com
    Re[4]: Трудные для ООП иерархии классов
    От: _wqwa США  
    Дата: 21.09.07 11:08
    Оценка:
    Здравствуйте, elmal, Вы писали:

    E>Здравствуйте, Кодёнок, Вы писали:


    Кё>>То есть предлагаешь иерархию использовать только для классификации их всех как "чисел", а автоматическую совместимость между ними реализовать через implicit conversion?

    E>В общем да, а вот в деталях может оказаться что и нет . От деталей реализации все зависит.

    Кё>>А как решить проблему sqrt?

    E>А какая проблема с sqrt? sqrt(Number number) и должен возвращать набор чисел. sqrt(4) = 2 и -2 насколько я помню. И собственно когда мы его будем возвращать — эти числа должно быть наиболее адекватного типа. Ну а sqrt(-1) должен возвратить комплексное число, вроде оно наже одно (блин, уже школьную программу забываю — ужас).

    Угу, комплексные числа с мнимыми путаешь
    Кто здесь?!
    Re: Трудные для ООП иерархии классов
    От: igna Россия  
    Дата: 21.09.07 12:34
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:

    Кё>... квадрат всегда является прямоугольником ...


    Изменяемый квадрат не всегда является изменяемым прямоугольником. А в программировании в отличии от математики квадраты и прямоугольники как правило изменяемы.
    Re[2]: Трудные для ООП иерархии классов
    От: COFF  
    Дата: 21.09.07 14:05
    Оценка:
    M>Забавное обсуждение
    M>Автор привел пару примеров задач, решение которых в рамках традиционного ООП является затруднительным, и попросил подкинуть еще (т.е. добавить убедительности, по сути).

    M>Но все это ни в малейшей степени не означает, что приведенные примеры не являются затруднительными для решения. Идеальный язык не будет навязывать свою парадигму мышления, он будет логично встраиваться в систему взглядов эксперта предметной области. Я так понимаю, что речь именно об этом.


    Так ведь суть в том, что это не задачи, а вопросы из серии — что было раньше, курица или яйцо, или с какого конца надо разбивать яйцо? А ведь эти проблемы легкими для решения тоже не назовешь. Другой вопрос, стоит ли их решать?
    Re: Трудные для ООП иерархии классов
    От: MatFiz Россия  
    Дата: 21.09.07 19:49
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:

    Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?). Другая трудность в том, что прямоугольник иногда может являться квадратом, но классические отношения между классами, которые предлагают ЯП (наследование и implicit-conversion) не могут выразить такого отношения.


    Одинаковый интерфейс, разные реализации (данные представлены по-разному).
    Тут все просто.


    public interface IRectangle
    {
        double Width { get; }
        double Height { get; }
    }
    
    public class Rectangle : IRectangle
    {
        readonly double _width;
        readonly double _height;
    
        public double Width { get { return _width; } }
        public double Height { get { return _width; } }
    }
    
    public class Square : IRectangle
    {
        readonly double _size;
    
        public double Size { get { return _size; } }
        public double Width { get { return Size; } }
        public double Height { get { return Size; } }
    }
    How are YOU doin'?
    Re[2]: Трудные для ООП иерархии классов
    От: Left2 Украина  
    Дата: 22.09.07 10:01
    Оценка:
    M>Идеальный язык не будет навязывать свою парадигму мышления, он будет логично встраиваться в систему взглядов эксперта предметной области.
    Ох как красиво сказал! Утопично, но как звучит!
    ... << RSDN@Home 1.2.0 alpha rev. 717>>
    Re[2]: Трудные для ООП иерархии классов
    От: deniok Россия  
    Дата: 22.09.07 10:52
    Оценка:
    Здравствуйте, mrozov, Вы писали:

    M>Но все это ни в малейшей степени не означает, что приведенные примеры не являются затруднительными для решения. Идеальный язык не будет навязывать свою парадигму мышления, он будет логично встраиваться в систему взглядов эксперта предметной области.


    Система взглядов эксперта в предметной области может оказаться довольно наивной и слабосовместимой с системой взглядов эксперта другой области. Если уж мы допускаем эксперта до ЯП, то это должен быть специализированный (e)DSL + визуальная среда, а никак не язык общего назначения. Что мы собственно и видим: VBA для офисных автоматизаторов, TeX/LaTeX для писателей научных статей, AutoLisp для труженников AutoCad, SQL для БДкопателей, встроенные языки математических пакетов для научных расчетов.

    В языке общего назначения всегда слишком много инструментов для поддержки собственно "програмистских" абстракций, которые предметникам совершенно не нужны.
    Re[2]: Трудные для ООП иерархии классов
    От: igna Россия  
    Дата: 23.09.07 08:15
    Оценка:
    Здравствуйте, MatFiz, Вы писали:

    MF>Одинаковый интерфейс, разные реализации (данные представлены по-разному).

    MF>Тут все просто.

    А setter-ы добавить сможешь?
    Re[4]: Трудные для ООП иерархии классов
    От: nikov США http://www.linkedin.com/in/nikov
    Дата: 23.09.07 09:01
    Оценка:
    Здравствуйте, igna, Вы писали:

    I>P.S. Параллелограмм это трапеция


    Это неверно. Смотреть любой учебник геометрии или здесь.
    Re[3]: Трудные для ООП иерархии классов
    От: jazzer Россия Skype: enerjazzer
    Дата: 23.09.07 15:55
    Оценка:
    Здравствуйте, deniok, Вы писали:

    D>Однако есть один момент. Когда ООП-ники говорят про преимущества ООП, одним из основных аргументов служит следующий:


    D>ОО проектирование легко позволяет моделировать окружающий мир.

    Так а в реальном мире прямоугольники и квадраты неизменяемые!
    Ты не можешь в геомтерии, из которой ты несешь идею "квадрат — это прямоугольник", изменить размеры ни квадрата, ни прямоугольника. Ты можешь только породить новый объект где-нть рядом ("по построению").
    В таком read-only интерфейсе между ними действительно есть строгое отношение "is a", и все операции, которые ты можешь применить в прямоугольнику (т.е. получение размеров, вычисление площади, получение координат вершин и т.п.) применимы и к квадрату.

    D>Видим в нём сотрудников — делаем класс Employee, видим начальника — делаем класс Manager, поскольку начальник is a сотрудник (в окружающем мире так) пользуем наследование.

    Сорри, поясни, в чем тут проблема?
    Я вот не вижу навскидку, что мы такого не можем сделать с сотрудником, чего не можем сделать с его начальником.
    Нанять/уволить можем? Можем.
    Зарплату заплатить или не заплатить можем? Можем.
    Дать людей в подчинение можем? Можем.
    Перекинуть его к другому начальнику можем? Можем.
    В чем проблема-то?

    D>Так вот проблемы с квадратом и прямоугольником как раз показывают, что по большому счёту эта простая схема — впендюринг.

    Эти примеры показывают, что ты берешь реальный мир из геометрии, в котором квадрат является прямоугольником, перемешиваешь его с виртуальным миром Visio/PowerPoint, в котором ты можешь менять размеры и того, и другого, и при этом не отсекаешь этого перехода и продолжаешь думать в терминах read-only геометрии.
    Это называется просто подменой понятий и к ООП отношение имеет опосредованное.
    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: Трудные для ООП иерархии классов
    От: jazzer Россия Skype: enerjazzer
    Дата: 23.09.07 16:31
    Оценка:
    Здравствуйте, Кодёнок, Вы писали:

    Кё>2. Комплексное число и вещественное число. Хотя вещественное число является комплексным (наследование), вы не станете наследовать его от комплексного по многим причинам: вам не нужна его реализация (два float в памяти вместо одного), вы вряд ли будете рады тому что sqrt(4) вместо 2.0 вернёт тупл из двух комплексных чисел, и т.п.


    Эта проблема, вообще-то, никакого отношения к ООП не имеет.

    В математике корень степени N из любого положительного числа на множестве действительных чисел будет возвращать действительное число, а на поле комплексных — N комплексных чисел.
    Соответственно, в математике одноименные функции над действитальными и комплексными числами записываются с маленькой и большой буквы соответственно, если мне память не изменяет, конечно.
    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[5]: Трудные для ООП иерархии классов
    От: igna Россия  
    Дата: 24.09.07 07:29
    Оценка:
    Здравствуйте, nikov, Вы писали:

    N>Это неверно. Смотреть любой учебник геометрии или здесь.


    В моем учебнике геометрии параллелограмм был частным случаем трапеции. Почитав русскую Википедию подумал сначала, что определение просто небрежно написано, но почитав английскую с удивлением обнаружил, что бывает и такое, исключающее частный случай параллелограмма, определение трапеции. Какой в нем смысл — для меня загадка, ведь вроде все доказательства и алгоритмы применимые к трапециям будут применимы и к параллелограммам, так к чему исключение? Подобные штуки в каком-нибудь языке программирования или в написанной на нем библиотеке меня скорее всего не удивили бы; но у математиков как правило все намного лучше продумано.
    Re[3]: Трудные для ООП иерархии классов
    От: mrozov  
    Дата: 24.09.07 09:11
    Оценка:
    История величайших изобретений (не путать с открытиями) состоит из восклицаний "почему я раньше до этого не додумался".

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

    DSL — это только один из вариантов развития. Затачивание языка под прикладную область/тип мышления. Было бы неплохо нащупать прорыв
    Re[4]: Трудные для ООП иерархии классов
    От: COFF  
    Дата: 24.09.07 09:54
    Оценка:
    Здравствуйте, igna, Вы писали:

    I>P.S. Параллелограмм это трапеция, а трапеция это четырехугольник. А еще и дельтоид есть.


    Насчет дельтоида не знал
    Re[3]: Трудные для ООП иерархии классов
    От: MatFiz Россия  
    Дата: 25.09.07 18:34
    Оценка:
    Здравствуйте, igna, Вы писали:

    I>А setter-ы добавить сможешь?


    Зачем они могут понадобиться?
    Лучше иметь immutable-классы — мороки потом меньше будет.
    How are YOU doin'?
    Re: Трудные для ООП иерархии классов
    От: Baudolino  
    Дата: 25.09.07 19:57
    Оценка:
    Кё>Я ищу примеры классов объектов, которые вызывают трудности при объектном моделировании в современных ЯП типа C++ или C#.
    С трудностями не встречался ни разу. Нужно просто знать некоторые приёмчики (паттерны и просто трюки) и правильно анализировать предметную область.

    Кё>1. Построить иерархию классов для прямоугольника и квадрата, с изменяющимися размерами. Трудность в том, что хотя квадрат всегда является прямоугольником (наследуется), он не захочет наследовать его реализацию (зачем ему раздельно хранить ширину и высоту?). Другая трудность в том, что прямоугольник иногда может являться квадратом, но классические отношения между классами, которые предлагают ЯП (наследование и implicit-conversion) не могут выразить такого отношения.

    Решение тривиально после правильного анализа, который заключается в том, что необходимо выделить интерфейс или абстрактный класс (как уже отмечали выше):
    public abstract class Figure {
       // координаты центра масс и 
       // угол поворота от некоторого положения по умолчанию (для прямоугольников - когда стороны параллельны осям)
       float x,y,a;
       abstract Figure rotate(float da);
       abstract Figure move(float dx, float dy);
       abstract Figure resize(float factor); // операция изменения размера производит подобную фигуру
       abstract void paint(Graphics g);
    }
    
    public abstract class Rectangle {
       // размеры: при угле равном 0, стороны соотв. ширине, параллельны оси OX
       abstract float getWidth();
       abstract float getHeight();
       abstract Rectangle move(float dx, float dy);
       // операция изменения размера производит подобную фигуру,
       // поэтому мы можем уточнить тип
       abstract Rectangle resize(float factor); 
       abstract Rectangle resize(float wfactor, hfactor);
       ...
    }
    
    public class GenericRectangle extends Rectangle {
       float x, y, a;
       float width, height;
       Rectangle resize(float factor) { return new GenericRectangle(x, y, a, width *factor, height * factor) }
       Rectangle resize(float wfactor, float hfactor) { return new GenericRectangle(x, y, a, width * wfactor, height * hfactor) }
       ...
    }
    
    public class Square extends Rectangle {
       float x,y,a,size;
       Square resize(float factor) { return new Square(x,y,a,size*factor); }
       Rectangle resize(float wfactor, hfactor) {
           if (wfactor == hfactor) {
               return new Square(x,y,a,size*wfactor);
           } else {
               return new GenericRectangle();
           }
       }
    }



    Кё>2. Комплексное число и вещественное число. Хотя вещественное число является комплексным (наследование), вы не станете наследовать его от комплексного по многим причинам: вам не нужна его реализация (два float в памяти вместо одного), вы вряд ли будете рады тому что sqrt(4) вместо 2.0 вернёт тупл из двух комплексных чисел, и т.п.

    Аналогично, реализация отделяется от наследования. Операции над числами реализуются в соответствующей алгебре:

    public interface Number {    
        double[] getTuple(); // возвращает 1,2 или 4 элемента (если угодно поддерживать экзотику, то можно 8 и 16)
        double get(int component); // возвращает значение соотв. компонента
    }
    public interface ComplexNumber implements Number {
        abstract double re();
        abstract double im();
    }
    public class GenericComplexNumber implements ComplexNumber {
        double[] tuple = new double[2];
    }
    
    public class RealNumber implements ComplexNumber {
        double[] tuple = new double[2];
        public double value() { return tuple[0]; }
    }
    
    public interface Algebra<N extends Number> {
        Number[] basis(); 
        double multiply(N n1,N n2);
        double add(N n1,N n2);
        ... // и другие операции для данной алгебры
    }
    
    public class ComplexAlgebra extends Algebra<ComplexNumber> {
        ComplexNumber[] sqrt(ComplexNumber number) { ... } 
    }
    
    public class RealAlgebra extends Algebra<RealNumber> {
        RealNumber sqrt(RealNumber number) { ... }
    }
    Re[2]: Трудные для ООП иерархии классов
    От: Шахтер Интернет  
    Дата: 26.09.07 01:33
    Оценка:
    Здравствуйте, jazzer, Вы писали:

    J>Здравствуйте, Кодёнок, Вы писали:


    Кё>>2. Комплексное число и вещественное число. Хотя вещественное число является комплексным (наследование), вы не станете наследовать его от комплексного по многим причинам: вам не нужна его реализация (два float в памяти вместо одного), вы вряд ли будете рады тому что sqrt(4) вместо 2.0 вернёт тупл из двух комплексных чисел, и т.п.


    J>Эта проблема, вообще-то, никакого отношения к ООП не имеет.


    J>В математике корень степени N из любого положительного числа на множестве действительных чисел будет возвращать действительное число, а на поле комплексных — N комплексных чисел.

    J>Соответственно, в математике одноименные функции над действитальными и комплексными числами записываются с маленькой и большой буквы соответственно, если мне память не изменяет, конечно.

    Изменяет.
    В XXI век с CCore.
    Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
    Re[2]: Трудные для ООП иерархии классов
    От: igna Россия  
    Дата: 30.09.07 09:46
    Оценка:
    Здравствуйте, Baudolino, Вы писали:

    Если не ошибаюсь, у тебя все объекты неизменяемые, так?
    Re[2]: Трудные для ООП иерархии классов
    От: no4  
    Дата: 01.10.07 07:41
    Оценка:
    Здравствуйте, igna, Вы писали:

    I>Здравствуйте, Кодёнок, Вы писали:


    Кё>>... квадрат всегда является прямоугольником ...


    I>Изменяемый квадрат не всегда является изменяемым прямоугольником. А в программировании в отличии от математики квадраты и прямоугольники как правило изменяемы.


    В книжке Шлеер и Меллора было понятие "миграция подтипа", насколько я помню. Т.е. объект может стать принадлежащим другому классу
    ... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
    Re[3]: Трудные для ООП иерархии классов
    От: Gaperton http://gaperton.livejournal.com
    Дата: 04.10.07 10:06
    Оценка:
    Здравствуйте, igna, Вы писали:

    I>Если не ошибаюсь, у тебя все объекты неизменяемые, так?


    Ну да, в первом примере он сделал методы, которые выводят экземпляр подкласса из этого подкласса константными, по другому никак, это единственное решение, не нарушающее принцип подстановки Лисков. Правильнее было бы вообще их наследованием не связывать, правда. Но это неважно в данном случае, решение все равно корректно.

    Во втором случае — с числами — решение просто неверно. Интерфейсы, которые он определил, не содержат операций, зато они дают полный доступ к атрибутам. Определенные им типы вообще не являются абстрактными типами данных, и принцип подстановки Лисков нарушается на раз-два-три. Правильное решение — сделать абстрактный класс "поле чисел", как в алгебре, и опять — не связывать оба типа чисел наследованием.

    И третье — все решения переусложнены, и вводят больше сущностей, чем необходимо.
    Re[5]: Трудные для ООП иерархии классов
    От: ZevS Россия  
    Дата: 05.10.07 08:52
    Оценка:
    Здравствуйте, Курилка, Вы писали:

    К>Почему безапелляционные?

    К>Возьмём 4-й пункт "У объектов есть private состояние" — с самим утверждением не будешь спорить, надеюсь?
    К>Джо говорит, что состояние — одна из проблем, состояние увеличивает зависимости, уменьшает расспараллеливаемость и т.д.
    К>"Обычные" языки пытаются "спрятать" состояние (с помощью модификаторов и т.п.), тогда как в декларативных функциональных есть подаваемые данные на вход и результат на выходе.

    Четвертый пункт — единственный, с которым можно согласиться. Все прочие пункы — просто утверждения.

    Почему "Since functions and data structures are completely different types of animal it is fundamentally incorrect to lock them up in the same cage."? А ОО утверждает, что все объекты реального мира имеют и состояние и поведенеие, и почему их надо программировать иначе?

    "But in a non OO language a "time" is a instance of a data type." — ну и что с того? А ОО языке — это объект. И что с этого?

    "Note that these definitions do not belong to any particular object. they are ubiquitous and data structures representing times can be manipulated by any function in the system." — а с ОО что не так? Использование вовсе != наследование.

    "In an OOPL I have to choose some base object in which I will define the ubiquitous data structure, all other objects that want to use this data structure must inherit this object." — ну а это вообще бред.
    Re[2]: вопрос с фигурами остаётся открытым
    От: madlax  
    Дата: 05.10.07 12:25
    Оценка:
    Baudolino,

    квадрат может находиться в произвольном количестве контейнеров и композитных фигур,
    при изменении размеров нужно менять экземпляр объекта в каждом контейнере
    как это будет выглядеть в коде? сможет квадрат сам подменить себя?
    Re[4]: Трудные для ООП иерархии классов
    От: jazzer Россия Skype: enerjazzer
    Дата: 06.10.07 14:37
    Оценка:
    Здравствуйте, Gaperton, Вы писали:

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


    I>>Если не ошибаюсь, у тебя все объекты неизменяемые, так?


    G>Ну да, в первом примере он сделал методы, которые выводят экземпляр подкласса из этого подкласса константными, по другому никак, это единственное решение, не нарушающее принцип подстановки Лисков. Правильнее было бы вообще их наследованием не связывать, правда.


    Почему, если не секрет?
    Как ты в языках типа С++ заставишь функцию, работающую с Figure, принимать объекты Rectangle и прочих, если они не связаны отношением наследования (т.е. абсолютно разные типы)?

    Или все на шаблонах будешь делать?
    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]: вопрос с фигурами остаётся открытым
    От: Sinclair Россия https://github.com/evilguest/
    Дата: 08.10.07 05:19
    Оценка:
    Здравствуйте, madlax, Вы писали:

    M>Baudolino,


    M>квадрат может находиться в произвольном количестве контейнеров и композитных фигур,

    M>при изменении размеров нужно менять экземпляр объекта в каждом контейнере
    M>как это будет выглядеть в коде? сможет квадрат сам подменить себя?
    Совершенно непонятно, что такое "находиться в контейнере", и что такое "изменение размеров".
    Если речь идет о квадрате с семантикой value-типа (к которой вы привыкли в геометрии), то никакого "изменения размеров" у него не может быть.
    Квадраты-значения ведут себя так же, как целые числа. Давайте перефразируем ваш вопрос:

    целое может находиться в произвольном количестве контейнеров и композитных фигур,
    при изменении значения нужно менять экземпляр объекта в каждом контейнере
    как это будет выглядеть в коде? сможет целое сам подменить себя?

    И попробуем представить пример. Каким значением вы собираетесь заменить число "пять"? Что будет с программой, в которой все пятерки превратятся в тройки?

    Если речь идет о CAD системе, то никакого value-type поведения у квадратов не будет. Квадрат окажется частным случаем ломаной; никаких чудес с взаимонаследованием от прямоугольников не произойдет, т.к. поведение квадрата как части объектной модели не будет накладывать никаких ограничений ни на углы, ни на равенство сторон, ни даже на их количество. В кадах применяется совсем другая алгебра; там есть примитивы merge и subtract, есть примитив group и так далее. Никакие "геометрические" свойства не будут инвариантами, и наследование не будет иметь никакого смысла.
    ... << RSDN@Home 1.2.0 alpha rev. 677>>
    Уйдемте отсюда, Румата! У вас слишком богатые погреба.
    Re[5]: Трудные для ООП иерархии классов
    От: Gaperton http://gaperton.livejournal.com
    Дата: 11.10.07 12:30
    Оценка:
    Здравствуйте, jazzer, Вы писали:

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


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


    I>>>Если не ошибаюсь, у тебя все объекты неизменяемые, так?


    G>>Ну да, в первом примере он сделал методы, которые выводят экземпляр подкласса из этого подкласса константными, по другому никак, это единственное решение, не нарушающее принцип подстановки Лисков. Правильнее было бы вообще их наследованием не связывать, правда.


    J>Почему, если не секрет?

    J>Как ты в языках типа С++ заставишь функцию, работающую с Figure, принимать объекты Rectangle и прочих, если они не связаны отношением наследования (т.е. абсолютно разные типы)?

    J>Или все на шаблонах будешь делать?


    Надо квадрат с прямоугольником наследованием не связывать. Толку от этого ноль в реальной ситуации, только проблемы. А вот от какого-то абстрактного Figure и то и другое наследовать можно, но ведь об этом в условии задачи ни слова, не так ли?
    Re[2]: Трудные для ООП иерархии классов
    От: Кодёнок  
    Дата: 12.10.07 06:51
    Оценка:
    Здравствуйте, Krovosos, Вы писали:

    K>Трудно ответить на вопрос, которые выдает с головой ваше непонимание смысла ООП, не в обиду будет сказано. Но я мужественно попробую


    Ответ на вопрос, которого не было, выдает с головой неясность и запутанность мышления. В моем письме не было вопроса

    По существу, иерархия — это не увеличение сложности. Иерархия это система отношений между типами. Отношения между типами нужны, потому что типы бывают взаимозаменяемыми. Иерархия это один из способов реализации подтипов: везде где требуется базовый класс, можно подставить дочерний. В довесок, ОО-языки совмещают это с наследованием реализации, хотя и не всегда, что имеет свои проблемы, некоторые из которых показаны.
    Re[3]: Трудные для ООП иерархии классов
    От: Krovosos  
    Дата: 12.10.07 17:49
    Оценка:
    K>>Трудно ответить на вопрос, которые выдает с головой ваше непонимание смысла ООП, не в обиду будет сказано. Но я мужественно попробую

    Кё>Ответ на вопрос, которого не было, выдает с головой неясность и запутанность мышления. В моем письме не было вопроса


    Значит мне показалось

    Кё>По существу, иерархия — это не увеличение сложности.


    Увеличение. Я же говорю возьмите три независимых класса и три класса, которые наследуют друг от друга. Где будет больше неопределенности в поведении?

    Кё>Иерархия это система отношений между типами. Отношения между типами нужны, потому что типы бывают взаимозаменяемыми.


    "Взаимозаеменямость" это всего лишь реализация интерфейсов. Иерархия (суть — наследование поведения) отсюда напрямую никак не вытекает.

    Кё>Иерархия это один из способов реализации подтипов: везде где требуется базовый класс, можно подставить дочерний. В довесок, ОО-языки совмещают это с наследованием реализации, хотя и не всегда, что имеет свои проблемы, некоторые из которых показаны.


    Еще раз говорю: определитесь с целью. Зачем именно нужно Вам подставлять дочерний вместо базового? Почему нельзя обойтись интерфейсами, зачем именно нужен общий базовый класс?

    Это иллюзия, что хорошая продуманная иерархия классов придает стройность и упрощает проекты. Все как раз наоборот.

    Чем идеальнее Вы развяжете классы и отсечете их друга от друга — тем проще будет жить.
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.