LINUX.ORG.RU

Как жить без множественного наследования?


0

0

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

Вот уткнулся сейчас в проблему вообще в банальном PHP...

Задача - есть набор классов (с большим набором методов) тех или иных web/db-ресурсов. Это может быть простой ORM-маппинг, может быть дерево, хитро извлекаемое из БД, список...

Их наследники - конкретные типы объектов. Грубо говоря - простая страничка сайта, или вывод сложной формы...

Это объекты могут группироваться не только по структуре, но и по логическому разделению.

Скажем, раздел фирм на сайте, но в нём могут быть простые страницы, деревья категорий, списки регионов и т.п.

Пока нам хватает стандартных настроек - всё прекрасно.

Но вот нам для _раздела сайта_ требуется ряд общих настроек. Например, идентификаторы баннеров, имя шаблона...

Если все виды страниц относятся к одному классу - опять прекрасно. Делаем промежуточный класс, где всё это прописываем, а уже от него наследуем наши страницы.

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

Будь у нас множественное наследование - никаких проблем. Скажем, дерево категорий наследуем от базового дерева и базового набора свойств раздела.

А вот без него - фиг.

Каким боком тут можно прикрутить те же интерфейсы, скажем - просто не представляю.

Как быть-то?

★★★★★
Ответ на: комментарий от Cris

Ну и манеры у тебя выражаться. Чем же ты тогда отличаешься от "лживого трепача"? Никак этот камень был запущен в мой огород? Ну, да бог с твоими манерами. Впрочем, что возьмешь?..

Ты неправильно воспринимаешь интерфейс. Это не ограничение на существование метода, это - _контракт_ на функциональность: мол, такой-то класс обязуется предоставить такие-то функции.

На счет копи-паста. Прежде всего, не нужно судить по себе. Потом действительно не нужно мешать в одну кучу интерфейсы и классы (как в C++). Множественное наследование классов - это самый настоящий overload, когда разное смешали в одно. Если научиться правильно отделять их, то тогда, может быть, все еще получится :)

В общем, никто не говорил, что ООП - это просто. На самом деле, интерфейсы - очень сложная штука, несмотря на свою кажующуюся простоту. И не следует так напирать на наследование кода. Сам код - постольку поскольку. Контракт, поддерживаемый объектом, куда важнее. То есть, более важно то, как тот или иной объект выглядит снаружи, а не изнутри.

Наконец, тебе тоже всего самого наилучшего!

dave ★★★★★
()
Ответ на: комментарий от Cris

Более кратко. Наследование класса - это специализация или сужение реализации относительно предка. Наследование же интерфейса - это добавление или расширение функционала как обязательства/контракта перед другими. Понимаешь разницу?

dave ★★★★★
()
Ответ на: комментарий от dave

> Ну и манеры у тебя выражаться. Чем же ты тогда отличаешься от "лживого трепача"? Никак этот камень был запущен в мой огород? Ну, да бог с твоими манерами. Впрочем, что возьмешь?..

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

> Ты неправильно воспринимаешь интерфейс. Это не ограничение на существование метода, это - _контракт_ на функциональность: мол, такой-то класс обязуется предоставить такие-то функции.

Контракт и есть ограничение. Установка неких рамок. Но собственно здесь мы говорим про те же вещи только разными словами.

Суть моего поста была указать, что интерфейсы сами по себе не больше чем тесты. Они как договор или манифестация намерения. Но за ними нет реализации. А потому их важность завышена.

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

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

Что предлагают Ява и С-диез? Интерфейсы не решат задачу Крон7. Они только составят договор. Предложи решение в рамках Явы или Шарпа. Возможно я ошибаюсь.

Cris
()
Ответ на: комментарий от Cris

Кажется что-то такое есть в проекте будущей версии C# или Java. Точно не помню в каком именно языке. В некотором классе задаются методы, которые могут быть применены ко всем наследникам этого класса. В общем что-такое похожее. Деталей уже не помню. Какой-то syntactic sugar.

На самом деле не вижу проблемы и сейчас. Если я правильно понимаю твою задачу, то обычно обхожусь вспомогательными классами. Например, сейчас пишу хелпер ResultStorageWriter для класса ResultStorage (хранилище смоделированных данных). Этот хелпер будет сохранять данные в виде XML. Уже есть хелпер ResultStorageExporter, который умеет экспортировать данные в виде CVS или в текстовом формате, понимаемым Excel и OpenOffice.org. Примечательно, что указанные хелперы могут быть применены к любому наследнику класса ResultStorage.

Правда тут могут возникнуть проблемы с разграничением доступа, чтобы хелперы могли вызвать особые "потаенные" методы, которые должны быть относительно закрыты от других. В Java помогает выставление такому методу пакетной видимости, в C#- видимости internal с жестким правилом никогда не использовать internal без особой на то причины внутри модуля. Кроме того, такой функционал должен быть заложен в базовый класс изначально.

Ты об этом говоришь?

Что касается C++, то здесь слишком много соблазна реализовать хелпер как базовый класс. Такая практика порочна. Обычно помогает тест "is".

dave ★★★★★
()
Ответ на: комментарий от dave

> То есть, более важно то, как тот или иной объект выглядит снаружи, а не изнутри.

+1E6. "Хороший интерфейс важнее хорошей реализации" (с) svu 1996 Сорри за нескромность.

svu ★★★★★
()
Ответ на: комментарий от dave

Здравствуйте,

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

Вопрос в первую очередь к KRoN73.

Почему Вы не замените PHP на С++. Еще раз прошу прощения, если вопрос звучит тупо. Поясню, откуда он возник.

Давно пишу на С++ (еще с 1-го издания Страуструпа). Сейчас нужно садиться за кусок кода, работающий на сервере. Типичный PHP (все на нем сидят + аналоги/конкуренты). Читал, что вместо PHP можно использовать все что угодно (perl - тоже многие используют, python - наверное, тоже кто-то пишет, С, С++ - ни одного упоминания, примера о том, что это используется).

Почему нельзя отказаться от PHP и писать код, генерирующих эти куски html на привычном, исхоженном вдоль и поперек C++?

1. Тяжело реализовать некоторые вещи? 2. Некоторые сервера поддерживают только PHP и не разрешают исполнять компилированнай код? 3. что-то еще?

Я не сталкивался с WEB-программированием. Теперь пришлось. Я на распутье. Или вникать в достаточно новый PHP или я смогу свои навыки в C++ примерить в этой области?

anonymous
()
Ответ на: комментарий от anonymous

Посмотрите на Java, а именно на JSP (Java Server Pages), Java Servlets и EJB (Enterprise Java Beans). Вам как программисту на C++ может понравится :)

dave ★★★★★
()
Ответ на: комментарий от KRoN73

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

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

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

например -- "соседские яблоки" это (isA) пища или нет?. в принципе, яблоки съедобны -- значит "это пища". принадлежащее соседу есть нельзя, потому что не твое -- значит "это не_пища". хотя сосед их может жрать. значит для соеда яблоки -- пища, а для тебя -- не_пища.

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

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

проблема в том, что, в последствии, копипаст отождествили с онтологиями и через манифистацию типов возвели в рамки контрактов.

зы: вообще терминология ООП -- это сплошная диверсия. в том смысле, что основные термины (класс, объект класса, наследование) по смыслу абсолютно не соответствуют их общепринятым значениям. отсюда постоянная путаница.

anonymous
()
Ответ на: комментарий от svu

>> То есть, более важно то, как тот или иной объект выглядит снаружи, а не изнутри.

> +1E6. "Хороший интерфейс важнее хорошей реализации" (с) svu 1996 Сорри за нескромность.

Поспорил бы с копирайтом, но со смыслом согласен на 100%. При правильно продуманном интерфейсе можно реализацию исправить или вообще заменить.

pitekantrop ★★★
()
Ответ на: комментарий от anonymous

> например -- "соседские яблоки" это (isA) пища или нет?. в принципе, яблоки съедобны -- значит "это пища". принадлежащее соседу есть нельзя, потому что не твое -- значит "это не_пища". хотя сосед их может жрать. значит для соеда яблоки -- пища, а для тебя -- не_пища.

Плохой пример. Это уже из области авторизации и разграничения доступа. :)

pitekantrop ★★★
()
Ответ на: комментарий от pitekantrop

> Это уже из области авторизации и разграничения доступа. :)

не совсем. разграничение доступа это ограничение на действия (можно или нельзя *сожрать*).

типы данных (которые определяют классы в ооп) -- это множества. элементы одного множества можно выражать через элементы другого (возможно накладывая какие-то ограничения: Минуты можно представить ЦелымиЧислами в диапазоне от 0 до 59).

именного такого рода отношение между Яблоками и Пищей имелось ввиду. отношение Яблок к категории Пищи можно рассматривать по многим *критериям*. скажем по степени зрелости, вкусовым качествам, степени свежести, товарному виду, стоимости и т.п. :)

зы: http://www.math.mcgill.ca/~rags/bang/context1.ps.gz

anonymous
()
Ответ на: комментарий от watashiwa_daredeska

> И вместо одиночного тоже. Наследование -- зло! Интересно, когда же, наконец, уберут наследование из ООП?

Ну да. И реальные пацаны при необходимости незначительного изменения поведения класса пишут (самые продвинутые -- генерируют) тонну оберток.

Гы! :-)

eugine_kosenko ★★★
()
Ответ на: комментарий от KRoN73

> Нет. В том-то и дело, что задача стоит в очень небольших (один метод - одна строка, число методов - несколько штук) расширениях крупных базовых классов.

Угу. Классический пример на использование миксинов. Или трейтсов :-).

eugine_kosenko ★★★
()
Ответ на: комментарий от KRoN73

> Но любой, даже самый тупой компилятор должен уметь отлавливать эти неодноначности на этапе компиляции.

Eiffel это делает "на ура". За что и стал для меня заменой C++.

> Так откуда тогда могут взяться неоднозначности?

Потому что все языки наперегонки пытаются разрешить программисту прострелить себе ногу :-).

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

eugine_kosenko ★★★
()
Ответ на: комментарий от jek_

> научить компилятор запрещать создание ромбиков

Вот народ -- хлебом не корми, дай что-нибудь запретить :-).

eugine_kosenko ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.