Прочитал тут высказывания Линуса Торвальдса по поводу С++ в частности и ООП вообще...
То, что Торвальдс - абсолютный моральный урод, никак не меняет того факта, что его слова иногда заставляют задуматься (примерно та же ситуация, как с некоторыми людьми на этом форуме, не будем показывать пальцем, да?).
Нужно оговориться, что я просто обожаю плюсы. Как человек, имеющий солидный опыт программирования на жаве, я полагаю, что плюсы обходят жаву на несколько порядков: совершенно неудобоваримые, слабосильные генерики, невозможность объявления константных методов/ссылок и отсутствие перегрузки операторов, на мой взгляд, перевешивают встроенную сборку мусора.
Но не суть. На протяжении многих лет нам пытались внушить, что главный принцип, управляющий ООП-разработкой - уменьшение "сцепленности" (англ. coupling) между компонентами системы; иными словами, объекты должны быть как острова в океане, обнесенные крепостными стенами, препятствующими любым попыткам заглянуть внутрь.
Торвальдс спорит с этим утверждением, указывая на простой факт: внутренняя кухня операционной системы лучше всего описывается вовсе не объектами, а системами объектов и взаимодействиями между ними. Следовательно, ООП с его "малой сцепленностью" сразу идет как бы далеко и надолго, и мы вынуждены вернуться к старой процедурной парадигме: данные и функции для работы с ними. Несколько раз (сразу нужно сказать, что нечасто) я встречался с чем-то подобным - например, когда проектировал свой видео-движок.
Текстура? Возьмем ее и закроем в черную коробочку, а юзеру выдадим интерфейс, который ни в коем случае не позволяет получить доступ к API-specific данным.
Но ведь для того, чтобы "активировать" текстуру, скажем, в прямом х..., нужен не один, а сразу два объекта: сама текстура и контекст. Причем ни один из объектов не должен быть в "абстрагированном" виде - для активации нам нужен именно прямо-хшный контекст и прямо-хшная текстура. А у нас получается - если передаем ссылку на интерфейс контекста в метод текстуры, внутри метода имеем прямо-хшную текстуру и абстрактный контекст, если наоборот - прямо-хшный контекст и абстрактную текстуру.
Варианты решения - либо ручное приведение типов (в углу кто-то ахает и роняет на пол бокал), либо синглтоны (ублюдство, т.к. сразу отпадает возможность использования нескольких контекстов), либо QueryInterface, либо использование того, что американцы называют "double dispatching". Последние два варианта по сути не отличаются, поэтому приведу листинг для дабл-диспатчинга:
class IContext { virtual void Bind(const ITexture &tex) = 0; }; ... class Context_DX; class ITexture { virtual void Bind( const Context_DX &context) const = 0; };
Метод IContext::Bind(), соответственно, вызывает ITexture::Bind(). Детали класса Context_DX, разумеется, прикрыты от пользователя ранними объявлениями, только что толку - срамоту он все равно уже видел. Уродливо? Весьма.
Как ни странно, в этом случае единственное красивое решение - возвращение к сишному, WinAPI-style программированию: дескрипторы и функции для работы с ними.
Кто что думает по этому поводу?
<правка> Поскольку были вопросы по поводу описанной проблемы, поясняю проще:
1. По правилам ООП, интерфейс скрывает детали реализации.
2. Я создаю два интерфейса IContext + ITexture и скрываю детали реализации, как положено.
3. Пока я работаю с каждым интерфейсом отдельно (случай "малой сцепленности"), все ОК.
4. Проблемы возникают, когда мне в одном и том же участке кода нужны одновременно детали реализации и контекста, и текстуры (случай "сильной сцепленности").
winter
> либо использование того, что американцы называют "double dispatching".
> Последние два варианта по сути не отличаются, поэтому приведу листинг для
> дабл-диспатчинга:
есть и мульти
innuendo
>> есть и мульти
Ясное дело, есть и мульти-диспатчинг для большего количества аргументов, но ведь решение-то все равно уродливое? Даже Бог с ней, с формой - оно по сути уродливое: мы фактически боремся с абстракцией, которую сами же и ввели.
winter
Вы придумали себе задачу которой нет.
Зачем вам две функции для двух рендеров, когда работает только один?
А если вы вздумали переключать их в реал тайме, то вам просто нечем заняться.
Проще сделать макросами->2 exe->ланчер
winter
> Кто что думает по этому поводу?
Думаю, что метод Bind не нужен интерфейсу ITexture. Собственно, как ненужен тут и double dispatch.
я думаю торвальдс - дибил
обертке над API пофиг на его проблемы, она знает как сбиндить текстуру по айди,знает где и какое устройство, да и вообще не видит тут проблемы
Ghost2
>> Думаю, что метод Bind не нужен интерфейсу ITexture. Собственно, как ненужен тут и double dispatch.
Еще раз: юзеру выдается интерфейс ITexture и интерфейс IDevice, скрывающие реализации Texture_GL и Device_GL. Для активации текстуры нужны Texture_GL и Device_GL, а у юзера есть только абстрактные интерфейсы. Так понятнее?
Pokimon
Ты тоже не очень понял проблему. Проблема не в поддержке двух рендеров, а в том, что я выдаю пользователю два урезанных интерфейса. А для "включения" текстуры нужны два "расширенных" интерфейса.
<правка> Давайте даже еще проще сформулируем:
1. По правилам ООП, интерфейс скрывает детали реализации.
2. Я создаю два интерфейса IDevice + ITexture и скрываю детали реализации, как положено.
3. Пока я работаю с каждым интерфейсом отдельно (случай "малой сцепленности"), все ОК.
4. Проблемы возникают, когда мне в одном и том же участке кода нужны одновременно детали реализации и девайса, и текстуры (случай "сильной сцепленности").
Beginner
>> я думаю торвальдс - дибил
Вот и у меня была такая же первоначальная реакция. А потом призадумался...
Торвальдс не дебил. Но при этом он уже сам признает, что текущая архитектура Linux - тупик, держащийся на костылях.
winter
> юзеру выдается интерфейс ITexture и интерфейс IDevice
Акцент сделаем на букве I. Вопрос в том, как мы получаем объект, реализующий IDevice и ITexture. Адекватно спроектированная система не допустит создания, гм, Texture_GL если был создан Device_dx (неадекватно-спроектированная тоже не допустит - возникнет рантайм ошибка)
winter
> (ублюдство, т.к. сразу отпадает возможность использования нескольких девайсов)
А оно надо? Тем более инициализация обоих API в пределах одного приложения...
winter
> что американцы называют "double dispatching"
Это явно не то место, где нужна двойная диспетчеризация.
crsib
>> Это явно не то место, где нужна двойная диспетчеризация.
В третий раз...
1. По правилам ООП, интерфейс скрывает детали реализации.
2. Я создаю два интерфейса IDevice + ITexture и скрываю детали реализации, как положено.
3. Пока я работаю с каждым интерфейсом отдельно (случай "малой сцепленности"), все ОК.
4. Проблемы возникают, когда мне в одном и том же участке кода нужны одновременно детали реализации и девайса, и текстуры (случай "сильной сцепленности").
>> Акцент сделаем на букве I. Вопрос в том, как мы получаем объект, реализующий IDevice и ITexture. Адекватно спроектированная система не допустит создания, гм, Texture_GL если был создан
>> Device_dx (неадекватно-спроектированная тоже не допустит - возникнет рантайм ошибка)
Ну а это тут вообще причем? Представь себе, что у меня только один АПИ. Проблема возникает, как только мы вводим абстрактные интерфейсы.
Убрал из первоначального сообщения два АПИ, чтобы люди не путались.
crsib
> Торвальдс не дебил. Но при этом он уже сам признает, что текущая архитектура
> Linux - тупик, держащийся на костылях.
Пруфлинк?
В IT сфере слово "тупик" имеет совсем другое значение, чем IRL.
х86 с самых первых лет держится на костылях. И ничего, существует.
а приведи пример 4 пункта
winter
> 1. По правилам ООП, интерфейс скрывает детали реализации.
Скрывает. Ключевое слово - интерфейс
winter
> 2. Я создаю два интерфейса IDevice + ITexture и скрываю детали реализации, как
> положено.
Предположим
winter
> 3. Пока я работаю с каждым интерфейсом отдельно (случай "малой сцепленности"),
> все ОК.
Нет не все, но об этом позже
winter
> 4. Проблемы возникают, когда мне в одном и том же участке кода нужны
> одновременно детали реализации и девайса, и текстуры (случай "сильной
> сцепленности").
winter
> Ну а это тут вообще причем? Представь себе, что у меня только один АПИ.
> Проблема возникает, как только мы вводим абстрактные интерфейсы.
Да хоть три. Ты сам отметил, что интерфейсы связаны. И сам говоришь слово интерфейс. Так вот, интерфейс не предоставляет реализации (можете считать меня Колумбом). Как следствие, приложение должно тем или иным образом позволять создавать реальный объект, предоставляющий реализацию интерфейса. Традиционно это Factory. Но. Интерфейс текстуры жестко связан с API. И, соответственно, для текстуры фабрикой является само устройство. То есть мы сначала создаем объект, реализующий IDevice, а затем у объекта IDevice запрашиваем ITexture. (И о чудо, MS тоже думает так и реализацию IDirect3DTexture* мы получаем от IDirect3DDevice*.) И на этом моменте кончаются наши проблемы с глубокой связанностью. Ну, по крайней мере они решаются гораздо красивей.
Pokimon
> Пруфлинк?
http://www.theregister.co.uk/2009/09/22/linus_torvalds_linux_bloated_huge/
> х86 с самых первых лет держится на костылях. И ничего, существует.
Во во. Корни те же что с ядром Linux. И Command set reference на два не худеньких тома.)))
Рендеру нужно прибиндить текстуру по айди,он обращается к обертке над API - Bind(fuckitall); Обертка ранее сама сооздала эту текстуру и вынесла ее айди извне для пользователя,разумеется девайс ей тоже известен,биндить она умеет
Где проблема?
Вот реально не догоняю
Тема в архиве.