Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
class CTank
: public ITank
{
DECLARE_META_CLASS();
std::shared_ptr< IEngine > m_pEngine;
std::shared_ptr< IGun > m_pGun;
};
// Let 'Gun' is main Tank property.
// By appending this line we allow to create tanks based on the gun types,
// e.g. if we have 'laser' default gun type we will be able to create 'laser' tank
RUN_BEFORE_MAIN( Impl::EnuqueueObjectTypesRegistration< CTank >( "Gun" ) );
IMPLEMENT_META_CLASS( CTank, "Tank" )
{
using namespace Properties;
REGISTER_PROPERTY( MakeProperty( &CTank::m_pEngine, "Engine" ).release() );
REGISTER_PROPERTY( MakeProperty( &CTank::m_pGun, "Gun" ).release() );
}
void CreateSomeTanks()
{
std::unique_ptr< ITank > p1 = ObjectFactory().CreateObject< ITank >( "{Laser}" );
auto a1 = MakeTransaction().MakeTrampoline( p1 );
assert( a1.GetProperty( "Engine" ) == "{Default}" );
assert( a1.GetProperty( "Gun" ) == "{Laser}" );
std::unique_ptr< ITank > p2 = ObjectFactory().CreateObject< ITank >( "{Nuclear}" );
auto a2 = MakeTransaction().MakeTrampoline( p2 );
assert( a2.GetProperty( "Engine" ) == "{Default}" );
assert( a2.GetProperty( "Gun" ) == "{Nuclear}" );
a2.SetProperty( "Gun\Ammo", "Uranium 235" );
}
int main()
{
TypeFactory factory;
factory.add<Foo>(fooType);
factory.add<Bar>(barType);
}
#include <map>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
template <class IdType, class Base>
class ObjectFactory : boost::noncopyable
{
public:
typedef IdType IdTypeUsing;
protected:
typedef boost::shared_ptr<Base> BasePtr;
typedef boost::function<BasePtr()> CreateFunc;
typedef std::map<IdType, CreateFunc> FactoryMap;
public:
BasePtr create(const IdType & id) const
{
typename FactoryMap::const_iterator it = map_.find(id);
return (it != map_.end()) ? (it->second)() : BasePtr();
}
void add(const IdType & id, CreateFunc func)
{
FactoryMap::iterator i = map_.find( id );
if ( i == map_.end() )
map_.insert( FactoryMap::value_type(id, func) );
else
i->second = func; // элемент уже есть: что то сделать, например, заменить
}
private:
FactoryMap map_;
};
template <class T>
class RegisterElement
{
public:
typedef boost::shared_ptr<T> TPtr;
public:
template <class Factory>
RegisterElement(Factory & factory, const typename Factory::IdTypeUsing & id)
{
if (class_registered_++ == 0) // Jerry Schwarz counter
factory.add(id, &CreateElmImpl);
};
private:
static TPtr CreateElmImpl() { return TPtr( new T() ); }
static int class_registered_;
};
template<class T> int RegisterElement<T>::class_registered_ = 0;
class XmlElement {};
ObjectFactory<std::string, XmlElement> XmlFactory;
class Pic : public XmlElement {};
namespace {
// элемент зарегистрируется гарантированно один раз
RegisterElement<Pic> RegisterElementPic(XmlFactory, "pic");
}
class Text : public XmlElement {};
namespace {
RegisterElement<Text> RegisterElementText(XmlFactory, "text");
}
В тексте написано много слов, но не написано главного.
Естественно, "добавлять классы" в фабрику и "хранить список классов" в фабрике язык C++ не позволяет.
Вместо этого для каждого класса создается объект creator (причем все классы creator-ов созданы на основе одного родительского класса), и именно он добавляется в фабрику через метод add(). И при создании объекта нужного класса через метод create(), вызывается соответствующий creator.
Ставим объекты на поток, паттерн фабрика объектов