I've developed as part of a game engine a template class for a factory which manages objects of one specific type. The factory handles initialization, destruction, and accessing previously created objects by string identifier.
It allows forwarding parameters to object constructors with variadic arguments, and is interfaced with a few freestanding functions within the namespace. Since each object type has its own factory, factories are created automatically and managed by the Game
class (in the actual code Game
is a singleton and handles a bunch of stuff but in the following simplified code, Game
just deletes all the automatically created factories for us).
The following code can be copied to a file and compiled, it runs as expected and includes a simple example. Compile with C++11 enabled.
#include <iostream>
#include <map>
#include <vector>
#include <functional>
#include <memory>
namespace TGE
{
class FactoryBase
{
public:
virtual void destroy() = 0;
};
class Game
{
public:
void manageFactory(FactoryBase* factory)
{
_factoryStack.push_back(factory);
}
void destroy()
{
while(!_factoryStack.empty())
{
_factoryStack.back()->destroy();
_factoryStack.pop_back();
}
}
private:
std::vector<FactoryBase*> _factoryStack;
} MyGame;
// Forward declare template function for friendship later in ObjectFactory
template<class ObjectClass>
std::vector<std::string> objectList();
template<class ObjectClass>
class ObjectFactory : public FactoryBase
{
public:
void destroy()
{
if(_instance != nullptr)
delete _instance;
}
static ObjectFactory<ObjectClass>* instance()
{
if(_instance == nullptr)
_instance = new ObjectFactory<ObjectClass>();
return _instance;
}
template<typename... Args>
std::shared_ptr<ObjectClass> createObject(std::string id, Args&&... args)
{
objectMap[id] = std::shared_ptr<ObjectClass>
(new ObjectClass(std::forward<Args>(args)...));
return objectMap[id];
}
std::shared_ptr<ObjectClass> getObject(std::string id)
{
if(objectMap.find(id) != objectMap.end())
return objectMap[id];
return nullptr;
}
void deleteObject(std::string id)
{
if(objectMap.find(id) != objectMap.end())
objectMap.erase(id);
}
private:
ObjectFactory<ObjectClass>() { MyGame.manageFactory(this); }
~ObjectFactory<ObjectClass>() {}
static ObjectFactory<ObjectClass>* _instance;
friend std::vector<std::string> objectList<ObjectClass>();
std::map<std::string, std::shared_ptr<ObjectClass>> objectMap;
};
template<class ObjectClass>
ObjectFactory<ObjectClass>* ObjectFactory<ObjectClass>::_instance = nullptr;
template<class ObjectClass, typename... Args>
std::shared_ptr<ObjectClass> construct(std::string id, Args&&... args)
{
return ObjectFactory<ObjectClass>::instance()->createObject(id, std::forward<Args>(args)...);
}
template<class ObjectClass>
std::shared_ptr<ObjectClass> acquire(std::string id)
{
return ObjectFactory<ObjectClass>::instance()->getObject(id);
}
template<class ObjectClass>
void destruct(std::string id)
{
ObjectFactory<ObjectClass>::instance()->deleteObject(id);
}
template<class ObjectClass>
std::vector<std::string> objectList()
{
std::vector<std::string> keys;
for(auto itr : ObjectFactory<ObjectClass>::instance()->objectMap)
{
keys.push_back(itr.first);
}
return keys;
}
}
class Rectangle
{
public:
Rectangle(int w, int h) : width(w), height(h) {}
void setVals(int w, int h)
{
width = w;
height = h;
}
void getVals()
{
std::cout << width << 'x' << height << std::endl;
}
private:
int width, height;
};
int main()
{
auto myRectangle = TGE::construct<Rectangle>("MyRectangle", 5, 10);
myRectangle->getVals();
myRectangle->setVals(10, 5);
TGE::acquire<Rectangle>("MyRectangle")->getVals();
TGE::MyGame.destroy();
return 0;
}
destroy
function? \$\endgroup\$Game
class which has a static destroy function to close the game, you call it just before returning 0 in yourmain
function to delete the game states, resource manager, object factories etc. Thedestroy
function in ObjectFactory is to delete the static instance of ObjectFactory, as the instance is private. \$\endgroup\$