// NeL - MMORPG Framework // Copyright (C) 2010-2019 Winch Gate Property Limited // // This source file has been modified by the following contributors: // Copyright (C) 2020 Jan BOON (Kaetemi) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #ifndef FACTORY_H #define FACTORY_H #include "types_nl.h" #include "debug.h" #include namespace NLMISC { /** Interface class for object registered in the factory. * This is for factory internal use, you should not need to use this class directly. */ template class IFactoryRegister { public: virtual ~IFactoryRegister() {} /// This method is called to create an instance of the factored object. virtual BaseClass *createObject(const typename BaseClass::TCtorParam &ctorParam) = 0; }; /** Factory implementation class. * the class take 2 template argument : * * BaseClass : the common base class for all factored object of one factory. * * KeyType : the type of the key that identify the factorable object (string by default). * * The factory conforms to singleton design pattern. * * BaseClass must provide a typedef for TCTorParam corresponding to the parameter * required by the constructor of factored object. */ template class CFactory { typedef std::map*> TRegisterCont; public: /// Get the singleton instance reference. static CFactory &instance() { // Singleton instance pointer. static CFactory instance; return instance; } /** Register a factorable object in the factory. * The method receive the key for this factorable object and * a pointer on the interface of a factory register object. */ void registerClass(const KeyType &key, IFactoryRegister *factoryRegister) { nlassert(_FactoryRegisters.find(key) == _FactoryRegisters.end()); _FactoryRegisters.insert(std::make_pair(key, factoryRegister)); } /** Create a new instance of a factorable object. * \param key the identifier of the object to create. * \param ctorParam the parameter for the constructor. * \return a pointer on the newly created object. */ BaseClass *createObject(const KeyType &key, const typename BaseClass::TCtorParam &ctorParam) { typename TRegisterCont::iterator it (_FactoryRegisters.find(key)); if (it == _FactoryRegisters.end()) return NULL; else return it->second->createObject(ctorParam); } // Add some introspection void fillFactoryList(std::vector &classList) { typename TRegisterCont::iterator first(_FactoryRegisters.begin()), last(_FactoryRegisters.end()); for (; first != last; ++first) { classList.push_back(first->first); } } protected: /// Singleton instance pointer. // static CFactory *_Instance; /// Container of all registered factorable object. TRegisterCont _FactoryRegisters; }; /** This class is responsible for creating the factorable object and to register * them in the factory instance. * You must declare an instance of this class for each factorable object. **/ template class CFactoryRegister : public IFactoryRegister { public: /** Constructor. * Register the factorable object in the factory. * /param key The identifier for this factorable object. */ CFactoryRegister(const KeyType &key) { FactoryClass::instance().registerClass(key, this); } /** Create an instance of the factorable class. * Implements IFactoryRegister::createObject */ BaseClass *createObject(const typename BaseClass::TCtorParam &ctorParam) { return new FactoredClass(ctorParam); } }; /** Macro to declare a factory. * Place this macro in an appropriate cpp file to declare a factory implementation. * You just need to specify the base class type and key type. */ //#define NLMISC_IMPLEMENT_FACTORY(baseClass, keyType) NLMISC::CFactory *NLMISC::CFactory::_Instance = NULL /** Macro to declare a factorable object. * Place this macro in a cpp file after your factorable class declaration. */ #define NLMISC_REGISTER_OBJECT(baseClass, factoredClass, keyType, keyValue) NLMISC::CFactoryRegister, baseClass, factoredClass, keyType> Register##factoredClass(keyValue) #define NLMISC_GET_FACTORY(baseClass, keyType) NLMISC::CFactory::instance() /** Interface class for object registered in the indirect factory. * This is for indirect factory internal use, you should not need to use this class directly. */ template class IFactoryIndirectRegister { public: virtual ~IFactoryIndirectRegister() {} /** Return the factory implementation.*/ virtual BaseFactoryClass *getFactory() = 0; }; /** Indirect factory implementation class. * the class take 2 template argument : * * BaseFactoryClass : the common base class for all factory object of one indirect factory. * * KeyType : the type of the key that identify the factorable object (string by default). * * The indirect factory conforms to singleton design pattern. * * In indirect factory, the object returned by the factory are not instance of factored object * but instance of 'sub' factory that do the real job. * This can be useful in some case, like adapting existing code into a factory * or having a complex constructor (or more than one constructor). */ template class CFactoryIndirect { typedef std::map*> TRegisterCont; public: /// Get the singleton instance reference. static CFactoryIndirect &instance() { static CFactoryIndirect instance; return instance; } void registerClass(const KeyType &key, IFactoryIndirectRegister *factoryRegister) { nlassert(_FactoryRegisters.find(key) == _FactoryRegisters.end()); _FactoryRegisters.insert(std::make_pair(key, factoryRegister)); } BaseFactoryClass *getFactory(const KeyType &key) { typename TRegisterCont::const_iterator it (_FactoryRegisters.find(key)); if (it == _FactoryRegisters.end()) return NULL; else return it->second->getFactory(); } // Add some introspection void fillFactoryList(std::vector &classList) { typename TRegisterCont::iterator first(_FactoryRegisters.begin()), last(_FactoryRegisters.end()); for (; first != last; ++first) { classList.push_back(first->first); } } protected: // static CFactoryIndirect *_Instance; TRegisterCont _FactoryRegisters; }; template class CFactoryIndirectRegister : public IFactoryIndirectRegister { SpecializedFactoryClass _FactoryClass; public: CFactoryIndirectRegister(const KeyType &key) { IndirectFactoryClass::instance().registerClass(key, this); } BaseFactoryClass *getFactory() { return &_FactoryClass; } }; //#define NLMISC_IMPLEMENT_FACTORY_INDIRECT(baseFactoryClass, keyType) NLMISC::CFactoryIndirect *NLMISC::CFactoryIndirect::_Instance = NULL #define NLMISC_GET_FACTORY_INDIRECT_REGISTRY(baseFactoryClass, keyType) NLMISC::CFactoryIndirect::getInstance() #define NLMISC_REGISTER_OBJECT_INDIRECT(baseFactoryClass, specializedFactoryClass, keyType, keyValue) NLMISC::CFactoryIndirectRegister, baseFactoryClass, specializedFactoryClass, keyType> RegisterIndirect##specializedFactoryClass(keyValue) #define NLMISC_DECLARE_OBJECT_INDIRECT(baseFactoryClass, specializedFactoryClass, keyType) extern NLMISC::CFactoryIndirectRegister, baseFactoryClass, specializedFactoryClass, keyType> RegisterIndirect##specializedFactoryClass #define NLMISC_GET_FACTORY_INDIRECT(specializedFactoryClass) RegisterIndirect##specializedFactoryClass.getFactory() } // namespace NLMISC #endif // FACTORY_H