Russian Qt Forum
Ноябрь 24, 2024, 03:06 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 2 [3] 4   Вниз
  Печать  
Автор Тема: Обсуждение архитектуры приложения. Пример с фабричным методом  (Прочитано 32774 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #30 : Июнь 15, 2012, 15:50 »

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

Создание объекта по ID может быть реализовано всяко и целью фабрики не является (скорее это побочный эффект). А вот когда начинается перебор типа "тот или этот объект должен быть создан" - тогда конечно фабрика.

Я, если позволите, одеяло на свою сторону опять потяну.
Так уж тяните если взялись Улыбающийся  Изложите условия задачи здесь, подумайте как сформулировать (и не отфутболивать по ссылке), обсудим. А то выходит как-то "а у меня вот в той задаче не вышло" - ну так у всех не все выходило и что с того? Обсуждение все равно практически в тупике, так что живой пример может быть полезен.

Записан
alexis031182
Гость
« Ответ #31 : Июнь 15, 2012, 16:13 »

оболочка объекта создается только один раз и только по запросу, если она не нужна, то она не создается, затем она регистрируется и при повторном её запросе, мы её не создаем, а используем существующую зарегистрированную. Почему мы проигрываем в быстродействии?? Изза поиска по map??
Вероятно возникло недопонимание. Я про map нигде не говорил. Под "созданием" объекта имел ввиду:
- поиск типа объекта по идентификатору (map, vector, ещё что-нибудь, без разницы);
- выделение памяти под новый объект (оператор new);
- инициализация параметров объекта входными данными.

Если у Вас "оболочка" объекта создаётся единожды, и другие объекты того же типа не создаются вообще, то получается у Вас совсем не фабрика в моём представлении, а что-то похожее на пул. То есть, создали объект предварительно, если понадобился - изъяли из пула, попользовались, а затем снова вернули назад.
Записан
alexis031182
Гость
« Ответ #32 : Июнь 15, 2012, 16:27 »

Так уж тяните если взялись Улыбающийся
Пытаюсь как могу Улыбающийся

Изложите условия задачи здесь, подумайте как сформулировать (и не отфутболивать по ссылке), обсудим. А то выходит как-то "а у меня вот в той задаче не вышло" - ну так у всех не все выходило и что с того? Обсуждение все равно практически в тупике, так что живой пример может быть полезен.
Нет, я не говорил, что не получилось. Как раз и сделал у себя в проекте реализацию фабрики. Но это оказалось медленным решением. Медленным, конечно же относительно, однако в моём случае это употребимо.

Суть задачи в обработке поступающих HTTP-запросов на сервер. Я отказался от использования одного лишь парсинга строк, поскольку хотелось максимально абстрагироваться от HTTP синтаксиса. Другими словами, на входе имеем HTTP-запрос в тексте, а на выходе - соответствующие классы самого запроса (GET, POST, HEAD и т.п.) и классы заголовков. Вот тут и поимел снижение производительности, т.к. на создание объектов классов и инициализацию их атрибутов входными значениями уходит относительно много времени. А учитывая, что поставлена задача на обработку 10000 запросов в секунду, имею не шибко нужный результат. Таким образом, традиционная фабрика, которая сейчас у меня реализована, мне не подходит по причине довольно жёстких условий задачи, хотя свою работу она выполняет вполне корректно. Поэтому я и написал свою заметку выше.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #33 : Июнь 15, 2012, 16:43 »

Суть задачи в обработке поступающих HTTP-запросов на сервер. ..
Diffuse, specular. BSP, phong shading и.т.п.- Вам это о чем-то говорит? Полагаю что нет, хотя в моей работе это термины самые базовые. Вот столько же (или еще меньше) у меня понятия о GET, POST, HEAD. Не желаете тратить время на формулировку понятную программисту С++, ну значит и нечего обсуждать. Не навязываюсь
Записан
alexis031182
Гость
« Ответ #34 : Июнь 15, 2012, 17:01 »

Diffuse, specular. BSP, phong shading и.т.п.- Вам это о чем-то говорит? Полагаю что нет, хотя в моей работе это термины самые базовые. Вот столько же (или еще меньше) у меня понятия о GET, POST, HEAD. Не желаете тратить время на формулировку понятную программисту С++, ну значит и нечего обсуждать. Не навязываюсь
Хм... дело не в нежелании. Согласен, что упустил из виду момент, что Ваша специализация может быть далека от веба. Хочу подчеркнуть, что именно непреднамеренно упустил это из виду. Просто у меня задача специфичная. Впрочем, ситуация, с которой я столкнулся, вполне может быть справедлива и для любого другого протокола, а не только HTTP.

Запрос HTTP можно представить в виде двухуровневого дерева классов. Первый уровень - это тип/команда запроса. Второй уровень - это заголовки запроса. Чтобы было понятно, приведу простой пример запроса:
Код:
GET /index.html HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9b5) Gecko/2008050509 Firefox/3.0b5
Accept: text/html
Connection: close
(пустая строка)
Здесь первая строка - это первый уровень. А все последующие строки - это второй уровень классов. Все они принадлежат первому уровню. Например, класс Request_GET содержит классы: Header_Host, Header_User_Agent, Header_Accept и др. Их в каждом запросе может быть довольно много. Соответственно фабрике приходится напрягаться по полной, прокручивая имеющийся у неё список возможных вариантов при каждом запросе. Потом ещё идёт инициализация вновь созданных объектов входными параметрами, проверка их корректности. И в общем-то выливается всё это в довольно длительное время.

Как-то так. Если снова написал непонятно, то наверное мне никак по другому. И, повторюсь, дело не в нежелании Улыбающийся
Записан
nata267
Гость
« Ответ #35 : Июнь 15, 2012, 17:26 »

оболочка объекта создается только один раз и только по запросу, если она не нужна, то она не создается, затем она регистрируется и при повторном её запросе, мы её не создаем, а используем существующую зарегистрированную. Почему мы проигрываем в быстродействии?? Изза поиска по map??
Вероятно возникло недопонимание. Я про map нигде не говорил. Под "созданием" объекта имел ввиду:
- поиск типа объекта по идентификатору (map, vector, ещё что-нибудь, без разницы);
- выделение памяти под новый объект (оператор new);
- инициализация параметров объекта входными данными.

Если у Вас "оболочка" объекта создаётся единожды, и другие объекты того же типа не создаются вообще, то получается у Вас совсем не фабрика в моём представлении, а что-то похожее на пул. То есть, создали объект предварительно, если понадобился - изъяли из пула, попользовались, а затем снова вернули назад.

Как это другие объекты того же типа не создаются?? к примеру на форме 4 объекта QLabel, QLineEdit, 2 QPushButton. У каждого свой набор свойств, которые загружаются в редактор свойств и для каждого объекта создается своя оболочка "список свойств объекта" и помещается в QMap<IdObjectKey, QObject*> ExtensionMap, где QObject* - это оболочка "список свойств объекта", а IdObjectKey - это ключ,  который представляет собой QPair<QString, QObject*>, где QString - id фабрики порождающей данный вид оболочек, QObject* - объект, чью оболочку данного вида мы храним в ExtensionMap
« Последнее редактирование: Июнь 15, 2012, 17:31 от nata267 » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #36 : Июнь 15, 2012, 17:42 »

принадлежат первому уровню. Например, класс Request_GET содержит классы: Header_Host, Header_User_Agent, Header_Accept и др. Их в каждом запросе может быть довольно много. Соответственно фабрике приходится напрягаться по полной, прокручивая имеющийся у неё список возможных вариантов при каждом запросе. Потом ещё идёт инициализация вновь созданных объектов входными параметрами, проверка их корректности. И в общем-то выливается всё это в довольно длительное время.
Пример: есть фабрика - загрузчик файлов, напр jpg, png, bmp (для простоты). Приходит файл напр yyyyy.xxx
который надо загрузить. Если тупенько подряд пробовать все загрузчики - да, медленновато. Это Ваш случай?
Записан
alexis031182
Гость
« Ответ #37 : Июнь 15, 2012, 17:43 »

Как это другие объекты того же типа не создаются??
Я лишь предположил Улыбающийся

к примеру на форме 4 объекта QLabel, QLineEdit, 2 QPushButton. У каждого свой набор свойств, которые загружаются в редактор свойств и для каждого объекта создается своя оболочка "список свойств объекта" и помещается в QMap<IdObjectKey, QObject*> ExtensionMap, где QObject* - это оболочка "список свойств объекта", а IdObjectKey - это ключ,  который представляет собой QPair<QString, QObject*>, где QString - id фабрики порождающей данный вид оболочек, QObject* - объект, чью оболочку данного вида мы храним в ExtensionMap
Ну а раз всё же есть создание объектов, то это вполне может относиться к тому случаю, на который я указал: поиск по id, создание нового объекта и его инициализация могут быть относительно затратны, исходя из специфики задачи. Безусловно, в Вашем случае с 4-мя виджетами думать о таких мелочах нет необходимости. В моём - необходимость имеется. А вроде бы, казалось, один и тот же паттерн.
Записан
alexis031182
Гость
« Ответ #38 : Июнь 15, 2012, 17:53 »

Пример: есть фабрика - загрузчик файлов, напр jpg, png, bmp (для простоты). Приходит файл напр yyyyy.xxx
который надо загрузить. Если тупенько подряд пробовать все загрузчики - да, медленновато. Это Ваш случай?
Похоже. Если применительно к изображениям, то я вынужден сначала по расширению файла пределить тип файла. Затем, создать объект класса загрузчика изображения. Наконец, прочитать параметры изображения (а их довольно много) и создать соответствующие им объекты классов, которые со значениями этих параметров будут работать. Последний пункт в случае с изображениями - глупость, обойтись можно одним классом загрузчика, но именно это мне приходится делать для работы с HTTP.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #39 : Июнь 15, 2012, 18:23 »

Похоже. Если применительно к изображениям, то я вынужден сначала по расширению файла пределить тип файла. Затем, создать объект класса загрузчика изображения. Наконец, прочитать параметры изображения (а их довольно много) и создать соответствующие им объекты классов, которые со значениями этих параметров будут работать. Последний пункт в случае с изображениями - глупость, обойтись можно одним классом загрузчика, но именно это мне приходится делать для работы с HTTP.
Это задача отой "оболочки" которая часто называется "inventory". В мапе значения хранятся как указатель на inventory который создан синглтоном. Пример
Код
C++ (Qt)
class CInventoryJPG : public CInventory {
virtual CImageLoader * Create( void ) { return new CLoaderJPG(); }
virtual bool ValidFileType( uint32 type ) { return CLoaderJPG::ValidType(type); }
virtual bool ValidExtension( const char * ext ) { return CLoaderJPG::ValidExtension(ext);  }
 
static CInventoryJPG mInstance;
};
 
Регистрируемся
Код
C++ (Qt)
theImageFactory->RegisterLoader(LOADER_TYPE_JPG. &CInventoryJPG::mInstance);
 
Теперь сваливаем всю черновую работу в инвентарь, напр

Код
C++ (Qt)
// пытаемся подобрать загрузчик по типу файла (4 байта на Mac)
LOADER_TYPE CImageFactory::GetLoaderByFileType( uint32 type);
 
// не получилось, тогда по расширению
LOADER_TYPE CImageFactory::GetLoaderByExtension( const char * ext );
 
Конечно, если мудаковатый юзер записал jpg как png - это не сработает, придется тупо перебирать до тех пор пока кто-то подойдет. Но так быват редко. Конечно все проверки очень быстрые - никаких классов мы не создаем, просто зовем статик методы. И даже не обязаны линейно перебирать - можно зарядить мапы для типов и расширений. А когда уже "прицелились" - создаем экземпляр. Все эти поиски в фабрику хорошо вписываются
« Последнее редактирование: Июнь 15, 2012, 18:30 от Igors » Записан
alexis031182
Гость
« Ответ #40 : Июнь 15, 2012, 18:53 »

Спасибо. Это очень похоже на то, как реализован QMetaType. Я через него сделал фабрику. Примечательно, что создание первого объекта через его метод construct() выполняется довольно медленно, а последующие вызовы идут значительно быстрее. Похоже, что кэшируются соответствия id конкретным типам классов.

Однако поиск соответствия id к типу класса не является самым затратным. Затратно также создание и инициализация входными параметрами. Конечно, затраты эти обычно даже и не берутся во внимание, но мне приходится. Я думаю о том, чтобы вообще исключить процесс создания объектов классов из фабрики, а забирать уже готовые, созданные ранее и инициализированные параметрами по умолчанию. В этом случае, не потребуется вызывать никаких конструкторов, а нужно будет лишь внести входные значения параметров в уже существующий объект. Естественно, что функционал фабрики по поиску соответствия id к конкретному типу класса должен быть сохранён. После того, как объект, полученный из фабрики, выполнит свою задачу, он должен быть возвращён обратно, чтобы вновь быть использованным в другом запросе. В общем, вроде и фабрика, но с функционалом, похожим на QThreadPool.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #41 : Июнь 15, 2012, 19:07 »

В этом случае, не потребуется вызывать никаких конструкторов, а нужно будет лишь внести входные значения параметров в уже существующий объект.
Ну не синглтон, т.к. 2 или более ниток. Но никто не мешает зарядить и держать обработчики для всех ниток, напр
Код
C++ (Qt)
CImageLoader * GetThreadLoaderByID( int ID )
{
 ThrIterator it1 = mThreadMap.find(QThread::currentThreadID);  // ищем мапу загрузчиков для данной нитки
 if (it1 != mThreadMap.end()) {
   TLIterator it2 = it1.second.find(ID);   // ищем созданный загрузчик в мапе данной нитки
   ... // и.т.д.
 }
}
 
Что "не очень стандартно" но, на мой взгляд, никаких прынцыпов не нарушает  Улыбающийся
« Последнее редактирование: Июнь 15, 2012, 19:33 от Igors » Записан
alexis031182
Гость
« Ответ #42 : Июнь 15, 2012, 20:11 »

Ну не синглтон, т.к. 2 или более ниток. Но никто не мешает зарядить и держать обработчики для всех ниток, напр
...
Да, почти так я и думаю делать. Единственное, для парсинга запросов буду использовать один тред (в нём же и будет пул готовых объектов запросов и заголовков), а пул тредов уже для обработки этих запросов. Думаю, что это должно положительно сказаться на производительности. Посмотрим.

Что "не очень стандартно" но, на мой взгляд, никаких прынцыпов не нарушает  Улыбающийся
Да и пофиг на принципы. Эффективное решение задачи подчас важнее следования стандартам.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #43 : Июнь 16, 2012, 11:36 »

Думаю, что это должно положительно сказаться на производительности.
Это не имеет отношения к теме, но базовые Qt классы (напр QString) довольно затратны. Вызов new на хорошей кратности часто уже тормоз, а о таких ягодках как QString::split (столь любимых молодежью) неудобно и говорить. Возможно нужна разумная примитивизация (в духе С) 
Записан
alexis031182
Гость
« Ответ #44 : Июнь 16, 2012, 11:52 »

Это не имеет отношения к теме, но базовые Qt классы (напр QString) довольно затратны. Вызов new на хорошей кратности часто уже тормоз, а о таких ягодках как QString::split (столь любимых молодежью) неудобно и говорить. Возможно нужна разумная примитивизация (в духе С) 
Тут не поспоришь, так и есть. QString оказался существенным тормозом. Тем более, что используемая им UTF-16 мне совершенно ни к чему. Сейчас я пока применяю QString, и кое где QStringList, но думаю впоследствии перейти либо на QByteArray, либо, если и тот не устроит, ограничиться char'ами.
Записан
Страниц: 1 2 [3] 4   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.228 секунд. Запросов: 22.