Comments 27
BaseBuilder'у очень не повредил бы виртуальный деструктор, а UnifiedFactory не плохо было бы сделать NonCopyable, всеж в нем есть поля указателей, хоть и в мапе…
+1
Я тоже искал готовые решения, но не нашел. Поэтому сделал свою фабрику. Я старался сделать ее максимально гибкой, и без использования макросов. По умолчанию все обьекты регистрируется динамически во время выполнения, но никто не мешает сделать статический инициализатор.
+1
Пардон, у меня теги не работают (вставлял линк в мессадже выше): habrahabr.ru/post/129202/
0
Да, ваше решение практически идентичное. Это говорит о том что решение удачное.
0
Лисапеды наше все :) можно посмотреть Реинкарнация COM'а, или как мы любим изобретать один и тот же велосипед снова и снова
0
Подобные решения очень часто стоят рядом со стратегиями. Я писал нечто подобное, но плохо дружу с макросами, поэтому получалось не очень красиво… Взял макросы на заметку.
0
В кутиме аналогичный прием уже столет в обед юзается, но без этих страшных макросов.
0
~UnifiedFactory(){qDeleteAll(m_builders);}
Закатали бы лучше в QScopedPointer'ы, заодно бы получили невозможность копировать объект и автоматическое удаление. Ну или в случае если копирование нужно, тогда QSharedPointer
+2
и накладные расходы на умный указатель. Нет, пусть будет попроще. По-поводу запрета копирования замечание принял.
-2
Что Вы будете делать в случае, если создаваемому объекту понадобится некий параметр при конструировании?
Как по мне, то регистрировать стоит не конечный класс, а его билдер, либо уже созданный объект класса с клонированием (прототип).
Еще, при необходимости, можно сделать шаблонный метод для конструирования классов конкретного типа (не базового). Это позволит в некоторых случаях избежать нежелательной конвертации к классу-наследнику.
Я использовал похожую конструкцию как IoC контейнер, но там у меня хранились объекты разных классов без общего предка (по принципу boost::any).
Как по мне, то регистрировать стоит не конечный класс, а его билдер, либо уже созданный объект класса с клонированием (прототип).
Еще, при необходимости, можно сделать шаблонный метод для конструирования классов конкретного типа (не базового). Это позволит в некоторых случаях избежать нежелательной конвертации к классу-наследнику.
Я использовал похожую конструкцию как IoC контейнер, но там у меня хранились объекты разных классов без общего предка (по принципу boost::any).
+2
>>Что Вы будете делать в случае, если создаваемому объекту понадобится некий параметр при конструировании?
Не буду использовать данную фабрику :) вообще в таких случаях я вместо аргументов в конструкторе делаю некий init()
>>Еще, при необходимости, можно сделать шаблонный метод для конструирования классов конкретного типа (не базового)
Если вы в данном контексте знаете конкретный класс, зачем его конструировать через фабрику?
Если же этот класс сам является базовым для какого-то подможества — в данной реализации правильнее засунуть фабрику в него.
Не буду использовать данную фабрику :) вообще в таких случаях я вместо аргументов в конструкторе делаю некий init()
>>Еще, при необходимости, можно сделать шаблонный метод для конструирования классов конкретного типа (не базового)
Если вы в данном контексте знаете конкретный класс, зачем его конструировать через фабрику?
Если же этот класс сам является базовым для какого-то подможества — в данной реализации правильнее засунуть фабрику в него.
0
>>Если вы в данном контексте знаете конкретный класс, зачем его конструировать через фабрику?
Клиентский код может иметь доступ к декларации класса, но при этом не уметь его конструировать.
Конечно, все зависит от конкретной ситуации, я просто делал нечто подобное и вспомнил об этом.
Пример того, что я делал см. ниже.
Клиентский код может иметь доступ к декларации класса, но при этом не уметь его конструировать.
Конечно, все зависит от конкретной ситуации, я просто делал нечто подобное и вспомнил об этом.
Пример того, что я делал см. ниже.
0
>> Как по мне, то регистрировать стоит не конечный класс, а его билдер
Да, была такая мысль. Такое решение может быть гибче. Можно использовать ту же фабрику но с кастомными билдерами, а можно с шаблонными. В будущем если понадобится — так и сделаю.
>> либо уже созданный объект класса с клонированием (прототип)
И такой вариант реализован, но он имеет смысл для более узкого круга задач и более трудоёмок: необходима реализация клонирования в каждом наследнике и расход памяти больше.
Да, была такая мысль. Такое решение может быть гибче. Можно использовать ту же фабрику но с кастомными билдерами, а можно с шаблонными. В будущем если понадобится — так и сделаю.
>> либо уже созданный объект класса с клонированием (прототип)
И такой вариант реализован, но он имеет смысл для более узкого круга задач и более трудоёмок: необходима реализация клонирования в каждом наследнике и расход памяти больше.
0
Хочу привести пример IOC контейнера, о котором я упоминал:
class CContainer
{
struct SortPred
{
public:
bool operator ()(const boost::any& one, const boost::any& two)
{
return one.type().before(two.type()) ? true : false;
}
};
std::set<boost::any, SortPred> m_objects;
public:
template<typename T>
void RegisterObject(T* pT)
{
m_objects.insert(boost::any(pT));
}
template<typename T>
T* GetObject()const
{
T* pT = NULL;
auto iter = m_objects.find(boost::any(pT));
if (iter == m_objects.end())
{
return NULL;
}
return boost::any_cast<T*>(*iter);
}
template<typename T>
void UnregisterObject(T* pT)
{
auto iter = m_objects.find(boost::any(pT));
if (iter != m_objects.end())
{
m_objects.erase(iter);
}
}
};
+1
UFO just landed and posted this here
1. Где вы вообще увидели MFC, и что за претензии к использованию C++11 в 2012 году?
2. std::set в примере, т.к. мне нужно было написать пример быстро и по сути (оригинальный код я показать не могу).
В оригинале у меня std::map с хитрым составным ключом, включающим в себя type_info + строчку.
Таким образом, что результатом поиска может быть только объект определенного типа (так же, как и в примере с std::set). Единственное отличие при использовании std::map это то, что я могу добавлять в контейнер любое количество объектов разного типа с нулевым ID (как и в примере), и несколько объектов одного типа с разными ID:
В общем, оригинальный пример мне показался перегруженным и я сократил его до std::set.
3. type_info::berofre() возвращает int, а не bool.
2. std::set в примере, т.к. мне нужно было написать пример быстро и по сути (оригинальный код я показать не могу).
В оригинале у меня std::map с хитрым составным ключом, включающим в себя type_info + строчку.
Таким образом, что результатом поиска может быть только объект определенного типа (так же, как и в примере с std::set). Единственное отличие при использовании std::map это то, что я могу добавлять в контейнер любое количество объектов разного типа с нулевым ID (как и в примере), и несколько объектов одного типа с разными ID:
A* a = container.GetObject<A>();
B* b1 = container.GetObject<B>("b1");
B* b2 = container.GetObject<B>("b2");
В общем, оригинальный пример мне показался перегруженным и я сократил его до std::set.
3. type_info::berofre() возвращает int, а не bool.
0
У вас статический объект для регистрации будет инициализирован для каждой единицы трансляции в которую включен заголовочный файл с макросом UF_REGISTER_DERIVED в результате регистрация может быть вызвана несколько раз.
чтобы избежать этого можно воспользоваться приемом который называется счетчик Шварца (Jerry Schwarz counter)
чтобы избежать этого можно воспользоваться приемом который называется счетчик Шварца (Jerry Schwarz counter)
template<class T>
class AutoRegistrer
{
public:
AutoRegistrer(const QString& name)
{
if (registered_++ == 0)
factory()->registerClass<T>(name);
}
private:
static int registered_;
};
template<class T> int AutoRegistrer<T>::registered_= 0;
+1
Sign up to leave a comment.
Yet another factory