I implemented a general object factory following the guidelines of Andrei Alexandrescu's book Modern C++ Design, so I can define a class hierarchy like this (I will write the code in the most simplified way, avoiding implementation details or memory allocation/deallocation issues; I'm aware of these things and I would like to focus the discussion on the main issue):
// File "base.h"
#include <string>
#include "singleton.h"
#include "object_factory.h"
class Base;
using SingletonBaseFactory = Singleton
<
ObjectFactory
<
Base, // Abstract product type
std::string, // Identifier type
Base* (*)() // Concrete product creator type
>
>;
class Base {
// Define the interface (virtual functions, virtual dtor)
public:
// Wrap the Factory method
static Base* Factory(const std::string& ID) {
return SingletonBaseFactory::Instance().Factory(ID);
}
};
// File "derived_1.h"
#include "base.h"
class Derived_1 : public Base { /* ... */ };
// File "derived_2.h"
#include "base.h"
class Derived_2 : public Base { /* ... */ };
and register each derived class within an anonymous namespace in the corresponding implementation file:
// File "derived_1.cpp"
#include "derived_1.h"
namespace {
Base* CreateDerived_1() {
return new Derived_1;
}
const bool registered = SingletonBaseFactory::Instance().Register("Derived_1", CreateDerived_1);
}
// Same for Derived_2 in file "derived_2.cpp"
Therefore, an user that wants to use this hierarchy in his code has just to invoke the Base::Factory
method with a proper identifier:
// File main.cpp
#include"base.h"
int main(){
Base* pb = Base::Factory("Derived_1");
// Do stuff with pb
return 0;
}
Now, suppose I have a template class hierarchy, say:
// File "baset.h"
#include <string>
#include "singleton.h"
#include "object_factory.h"
template<class T>
class BaseT;
template<class T>
using SingletonBaseTFactory = Singleton
<
ObjectFactory
<
BaseT<T>, // Abstract product type
std::string, // Identifier type
BaseT<T>* (*)() // Concrete product creator type
>
>;
template<class T>
class BaseT {
/*Define the interface*/
public:
BaseT Factory(const std::string& ID) {
return SingletonBaseTFactory<T>::Instance().Factory(ID);
}
};
// File "derivedt_1.h"
#include "baset.h"
template<class T>
class DerivedT_1 : public BaseT<T> { /* ... */ };
In this case the registration is an user responsibility for each type T he wants to use, before using the class hierarchy:
// File main.cpp
#include "baset.h"
#include "derivedt_1.h"
bool register_derived_1_int = SingletonBaseTFactory<int>::Instance().Register("Derived_1", [](){ return new DerivedT_1<int>; });
int main() {
BaseT<int>* pb = BaseT<int>::Factory();
return 0;
}
Keeping in mind that the ID of each derived template class is the same for every type T
, would it make sense to delegate the registration responsibility to the developer of each derived class (rather than the user) even in the templated case? If so, is there a workaround to achieve it?
Aucun commentaire:
Enregistrer un commentaire