Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Kluev, Вы писали:
K>>Да ничего МС не готовил. Возьми ту же МФЦ, где там успешное приготовление?
VD>Ты Ворд возьми на С писанный. Эксель плюсовый. Саму виндовс. Все они прошли эволюцию от огромного монолита до компонентных продуктов. А МФЦ — это левая библиотечка котору в МС используют раз в код для написания продуктов вроде Вордпэда.
В итоге програмировать под эту компонентную кучу мусора стало настолько неудобно, что даже в МС решили кровь сменить дотнетом. И кстати дотнетный АПИ это как раз откат от чистой компонентности в стиле СОМ к статичекому связыванию. Ты же классы напрямую юзаешь, а не через интерфейсы.
K>>P/S А насчет компонентного подхода, так в своих прогах я от него отказался, а почему? VD>Потому что у тебя нет команды из сотни разработчиков.
Ерунда. Во первых не поэтому, а потому, что я старый и мудрый А во вторых к примеру линкусовое ядро монолит и пишется целой толпой и ничего. Была еще такая чудная прога автокад, так там тоже весь API был ввиде библиотек С++ классов, очень удобно было юзать.
K>> Да потому что компонентность реально требуется только в плагинах, да и то это можно сделать только наполовину компонентным. Т.е. компонентный только плагин. Щас разьясню подробнее.
VD>Это потому что вы не умете ее готовить.
Умею, поверь мне. Юзал и СОМ и сам несколько фреймворков своих написал. Чистая компонентность не нужна и неудобна. Удобно когда сама прога имеет статический апи, а вокруг уже куча динамических компонентов.
Здравствуйте, Kluev, Вы писали:
K>В итоге програмировать под эту компонентную кучу мусора стало настолько неудобно, что даже в МС решили кровь сменить дотнетом. И кстати дотнетный АПИ это как раз откат от чистой компонентности в стиле СОМ к статичекому связыванию. Ты же классы напрямую юзаешь, а не через интерфейсы.
Ну спорить с тобой о дотнете я не буду. Просто потому, что не интересно. Ты ведь и в этой области больше меня знаешь.
VD>>Потому что у тебя нет команды из сотни разработчиков.
K>Ерунда.
А что есть? Ну, а раз нет, то от чего же ерунда?
K> Во первых не поэтому, а потому, что я старый и мудрый
Да. Действительно. Старость не радость.
K> А во вторых к примеру линкусовое ядро монолит и пишется целой толпой и ничего.
Оно не такое уж большое. А все остальное точно так же на компонентной основе реализовано. Драйвер тоже своего рода компонент.
VD>>Это потому что вы не умете ее готовить.
K>Умею, поверь мне.
Рад бы, да не выходит.
K> Юзал и СОМ и сам несколько фреймворков своих написал. Чистая компонентность не нужна и неудобна. Удобно когда сама прога имеет статический апи, а вокруг уже куча динамических компонентов.
Ну, тебе виднее. Ты же старый и оптыный.
... << RSDN@Home 1.1.4 beta 3 rev. 207>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Kluev, Вы писали:
K>>Ты же классы напрямую юзаешь, а не через интерфейсы.
AVK>С чего ты взял что связывание при этом статическое?
Имеется ввиду связывание с реализацией.
Ты же пишешь:
Foo f = new new Foo(); — конкретный класс реализация
а не:
а не IFoo а = CreateObject("Foo") — неизвестный класс реализации
Здравствуйте, VladD2, Вы писали:
VD>Оно не такое уж большое. А все остальное точно так же на компонентной основе реализовано. Драйвер тоже своего рода компонент.
Об этом и речь. Именно такой стиль я и использую. Некомпонентное ядро (со статическим апи) + плагины (сделаные как компоненты).
Здравствуйте, Kluev, Вы писали:
K>Имеется ввиду связывание с реализацией. K>Ты же пишешь: K>Foo f = new new Foo(); — конкретный класс реализация
K>а не: K>а не IFoo а = CreateObject("Foo") — неизвестный класс реализации
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Kluev, Вы писали:
K>>Имеется ввиду связывание с реализацией. K>>Ты же пишешь: K>>Foo f = new new Foo(); — конкретный класс реализация
K>>а не: K>>а не IFoo а = CreateObject("Foo") — неизвестный класс реализации
AVK>И в чем разница?
Хм. А ты отличий не нашел?
Тогда попробую обьяснить. Во первых от CreateObject("Foo") не занаследуешься. Т.к. класс реализации не известен. Во вторых когда все через интерфейсы это просто неудобно и не быстро: лишний уровень виртаулизации. В третих создание обьектов либо через фабрику либо в интерфейсе должны быть производящие функции, тоже не гуд.
Особенно когда есть такой код:
void node_doWork( DataNode &node )
{
DataNode child( node, "relative/path/to/child/node" );
int x = child.someVal_get();
}
// а когда все через интерфейсы:void node_doWork( IDataNode &node )
{
IDataNode *child = node.child_open("relative/path/to/child/node");
int x = child->someVal_get();
child->close();
}
// казалось бы все тоже самое, а когда есть сборка мусора, тогда еще и не надо заботится о child->close()
// Однако вот еще другой пример:void node_doWork( DataNode &node )
{
MyCoolDataNode child( node, "relative/path/to/child/node" );
int x = child.someVal_get();
child.myWork();
}
Т.е. когда все компонентно и через интерфейсы, программирование становится геморойным. Мудрые мужи стремятся минимизировать геморой и посему минимзация компонентности в программе это верное решение.
Монолит надо разбивать не на компоненты, а на модули (dll-библиотеки классов с устойчивым апи и обратной двоичной совместимостью). А вот модули уже можно обвешивать разного рода плагинами и компонентами. При этом плагины связываются с модулями (dll) статически и юзают АПИ напрямую а не через интерфейсы.
Здравствуйте, Kluev, Вы писали:
AVK>>И в чем разница?
K>Хм. А ты отличий не нашел?
K>Тогда попробую обьяснить. Во первых от CreateObject("Foo") не занаследуешься. Т.к. класс реализации не известен.
Это хорошо или плохо?
K> Во вторых когда все через интерфейсы это просто неудобно и не быстро: лишний уровень виртаулизации.
Зависит от конкретной задачи.
K> В третих создание обьектов либо через фабрику либо в интерфейсе должны быть производящие функции, тоже не гуд.
K>Т.е. когда все компонентно и через интерфейсы, программирование становится геморойным. Мудрые мужи стремятся минимизировать геморой и посему минимзация компонентности в программе это верное решение.
Мудрые мужи стараются не придерживаться замшелых принципов и позволяют от компонентов наследоваться.
K>Монолит надо разбивать не на компоненты, а на модули (dll-библиотеки классов с устойчивым апи и обратной двоичной совместимостью).
А компонент это и есть модуль с ОО-интерфейсом доступа, чтобы там не говорили некоторые товарищи. Главная фишка компонента — динамическое связывание, все остальное это особенности конкретных реализаций.
Здравствуйте, AndrewVK, Вы писали:
AVK>А компонент это и есть модуль с ОО-интерфейсом доступа, чтобы там не говорили некоторые товарищи. Главная фишка компонента — динамическое связывание, все остальное это особенности конкретных реализаций.
Ну что ж такое определение меня вполне устраивает. Просто если вернутся к мысли которую я толкал в начале ветки, то для большинства (80-90%) компонентов, вполне достаточно обычного С++ плюс DLL плюс паттерн P-Impl (обеспечивающий двоичную совместмость). Будет обеспечена компонентность и при этом исключается лишний уровень виртуализации. И при этом не надо городить огород типа СОМ и т.п.
Здравствуйте, Kluev, Вы писали:
K>Здравствуйте, AndrewVK, Вы писали:
AVK>>А компонент это и есть модуль с ОО-интерфейсом доступа, чтобы там не говорили некоторые товарищи. Главная фишка компонента — динамическое связывание, все остальное это особенности конкретных реализаций.
K>Ну что ж такое определение меня вполне устраивает. Просто если вернутся к мысли которую я толкал в начале ветки, то для большинства (80-90%) компонентов, вполне достаточно обычного С++ плюс DLL плюс паттерн P-Impl (обеспечивающий двоичную совместмость). Будет обеспечена компонентность и при этом исключается лишний уровень виртуализации. И при этом не надо городить огород типа СОМ и т.п.
Что понимаеися под паттерном P-IMPL + двоичная совместимость ? Не совсем вас понимаю ...
Здравствуйте, Kluev, Вы писали:
K>Ну что ж такое определение меня вполне устраивает. Просто если вернутся к мысли которую я толкал в начале ветки, то для большинства (80-90%) компонентов, вполне достаточно обычного С++ плюс DLL плюс паттерн P-Impl (обеспечивающий двоичную совместмость). Будет обеспечена компонентность и при этом исключается лишний уровень виртуализации.
Увы нет. Как показывает практика — без мощной RTTI такая компонетность оказывается неполноценной. Да и надежность подобного решения оставляет желать лучшего.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Kluev, Вы писали:
K>>Ну что ж такое определение меня вполне устраивает. Просто если вернутся к мысли которую я толкал в начале ветки, то для большинства (80-90%) компонентов, вполне достаточно обычного С++ плюс DLL плюс паттерн P-Impl (обеспечивающий двоичную совместмость). Будет обеспечена компонентность и при этом исключается лишний уровень виртуализации.
AVK>Увы нет. Как показывает практика — без мощной RTTI такая компонетность оказывается неполноценной. Да и надежность подобного решения оставляет желать лучшего.
Это далеко не всегда нужно. Даже поддержку динамического создания и то приходится делать в редких случаях. Мне этого хватает. А насчет надежности несовсем понял, где здесь грабли? Не удалять методов из класса и не менять порядок обьявления виртуальных функций. И все будет ок. А в классах где есть наследование можно про запас обьявить штук пять-десять виртуальных функций про запас, на редкий случай расширения.
class MY_API MyClass
{
struct MyClass_imp *imp_; // это реализация, можно менять как угодноpublic:
void foo(); // а это интерфейсvoid bar(); // руками не трогать!
};
// где MY_API - это __declspec(dllexport/dllimport)
Здравствуйте, Kluev, Вы писали:
K>Здравствуйте, Aviator, Вы писали:
K>Это вкратце вот так: K>
K>class MY_API MyClass
K>{
K> struct MyClass_imp *imp_; // это реализация, можно менять как угодно
K>public:
K> void foo(); // а это интерфейс
K> void bar(); // руками не трогать!
K>};
K>// где MY_API - это __declspec(dllexport/dllimport)
K>
Не совсем понимаю — и причём тут двоичная совместимость ???
Да и потом при таком подходе придётся всё на одном компиляторе компилить, то есть про написал, скомпили в ДЛЛ и забыл можно забыть...
Здравствуйте, Aviator, Вы писали:
A>Не совсем понимаю — и причём тут двоичная совместимость ???
Было написано "обратная двоичная совместимость". Т.е. старые модули будут работать с новыми dll без перекомпиляции.
A>Да и потом при таком подходе придётся всё на одном компиляторе компилить,
А на двух зачем компилить?
Здравствуйте, Kluev, Вы писали:
K>Здравствуйте, Aviator, Вы писали:
A>>Не совсем понимаю — и причём тут двоичная совместимость ??? K>Было написано "обратная двоичная совместимость". Т.е. старые модули будут работать с новыми dll без перекомпиляции.
A>>Да и потом при таком подходе придётся всё на одном компиляторе компилить, K>А на двух зачем компилить?
Да потому что нету например желания возится со старыми отлаженными исходниками, писавшимися людьми которых давно уже нет в обозримом пространстве и о принципах работы которых можно только догадываться . В том же COM'е сделал кмпонент, прицепил к основной программе и забыл о нём...
А с Вашим подходом придётся периодически например перекомпилить исходные коды, авозиться с кодом и т.п... ну не удобно это ...
Тогда я ьы уж лучше предложил деать что — то типа своего простенького комоподобного подхода на С++
в длл:
// отдельный MuClass.hclass IMyClass {
public:
virtual void f1() = 0;
virtual void f2() = 0;
};
// проект DLLclass MyClass : public IMyClass {
public:
virtual void f1() {
// your implementation
}
virtual void f2() {
// your implementation
}
};
void* loadClass() {
return new MyClass();
}
К основной программе цепляем MyClass.h и загружаем класс
IMyClass pMyClass = (IMyClass*) loadClass();
Здравствуйте, Kluev, Вы писали:
K>Это далеко не всегда нужно.
Но весьма часто. Design-time вобще без этого невозможен.
K> Даже поддержку динамического создания и то приходится делать в редких случаях. Мне этого хватает. А насчет надежности несовсем понял, где здесь грабли?
Грабли в том что несоответствие форматов VMT порушит твое приложение. Причем причину ты будешь искать долго.
K> Не удалять методов из класса и не менять порядок обьявления виртуальных функций. И все будет ок.
А если удалить?
K> А в классах где есть наследование можно про запас обьявить штук пять-десять виртуальных функций про запас, на редкий случай расширения.
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, Kluev, Вы писали:
K>>Это далеко не всегда нужно.
AVK>Но весьма часто. Design-time вобще без этого невозможен.
design time как правило нужен только для UI, а возьми к примеру АПИ какой нить системы типа PRO/E, acad или solidworks. К чему там дезигн-тайм? там его и применить то негде.
K>> Даже поддержку динамического создания и то приходится делать в редких случаях. Мне этого хватает. А насчет надежности несовсем понял, где здесь грабли?
AVK>Грабли в том что несоответствие форматов VMT порушит твое приложение. Причем причину ты будешь искать долго.
Не порушит т.к. компилер-то один юзается, о чем и сказано в доках. А кто не понял, я не виноват.
K>> Не удалять методов из класса и не менять порядок обьявления виртуальных функций. И все будет ок.
AVK>А если удалить?
А зачем? Даже если и удалишь то обнаружишь очень быстро. Системы выплюнет сообщение что функция в DLL не найдена.
K>> А в классах где есть наследование можно про запас обьявить штук пять-десять виртуальных функций про запас, на редкий случай расширения. AVK>Самому не смешно?
А чего смеятся, все так и делают. Посмотри например GTK, там честенько резервируют. Мудрые мужи знают что живут в мире где не может быть идеальных решений. Такой подход работает хорошо и с минимумом усилий.
Здравствуйте, Aviator, Вы писали:
A>>>Да и потом при таком подходе придётся всё на одном компиляторе компилить, K>>А на двух зачем компилить?
A>Да потому что нету например желания возится со старыми отлаженными исходниками, писавшимися людьми которых давно уже нет в обозримом пространстве и о принципах работы которых можно только догадываться . В том же COM'е сделал кмпонент, прицепил к основной программе и забыл о нём...
Это типичные заблуждения начинающего, об исходниках, удобстве и "сделал и забыл".
A> А с Вашим подходом придётся периодически например перекомпилить исходные коды, авозиться с кодом и т.п... ну не удобно это ...
С моим подходом не прийдется.
A> Тогда я ьы уж лучше предложил деать что — то типа своего простенького комоподобного подхода на С++
Ты мне сейчас предлагаешь связатся с гемороем от которого я уже пару лет как отказался.
A>К основной программе цепляем MyClass.h и загружаем класс A> IMyClass pMyClass = (IMyClass*) loadClass();
A> Ну что — то типа этого...
Здравствуйте, Kluev, Вы писали:
K>Здравствуйте, Aviator, Вы писали:
A>>>>Да и потом при таком подходе придётся всё на одном компиляторе компилить, K>>>А на двух зачем компилить?
A>>Да потому что нету например желания возится со старыми отлаженными исходниками, писавшимися людьми которых давно уже нет в обозримом пространстве и о принципах работы которых можно только догадываться . В том же COM'е сделал кмпонент, прицепил к основной программе и забыл о нём...
K>Это типичные заблуждения начинающего, об исходниках, удобстве и "сделал и забыл".
Даааааааа ?? Да что вы говорите ... Лично знаю контору где сделал компоненту, сгенерил длл-ку, свалил в общее хранилище и всё, с чужим кодом вообще никто не работает почти, то что сделано то рабоает, что работает плохо переписывается полностью, вся система состоит из кучи небольших длл-лек.
K>Полный отстой. Это даже хуже чем СОМ
Ну если руки кривые то всё полный отстой . Вот экспорт классов — это уж точняк редкостный изврат и в принципе не может быть хорошим решением, хотя бы потому что жёстко привязано к конкретному компилятору.
... Кстати, чем же полный отстой фабрика классов, можно узнать ?
ЗЫ Разумные люди пытаются использовать то хорошее что есть в каждом подходе и находить компоромиссные решения, а не придумывать принципы на пустом месте.