#include <list>
#include <iostream>
// Bazowy kreator jak u Ciebie - nie musi w zasadzie byc szablonem.
template <typename AbstractProduct>
class CreatorBase {
public:
// Implementacja konstruktora ponizej.
CreatorBase();
virtual AbstractProduct *create() = 0;
};
// Klasa tworzaca te rozne klasy w taki sam sposob jak u Ciebie.
// "Wadami" takiego rozwiazania jest to, ze instancje tej klasy musza istniec
// przez caly czas dzialania programu. W poprzednim podejsciu mozna bylo sobie
// rejestracje zrobic gdziekolwiek i kiedykolwiek.
template <typename AbstractProduct, typename ConcreteProduct>
class Creator : public CreatorBase<AbstractProduct> {
public:
Creator() {};
virtual AbstractProduct *create() { return new ConcreteProduct; }
};
// Prosta fabryka korzystajca z kreatorow wyzej.
// To jest singleton - to ten fakt rozwiazuje problemy kolejnosci statycznej
// inicjalizacji. Niektorzy twierdza, ze singletony sa zle.
// Jezeli bedziesz chcial uzywac tego w bibliotece wspoldzielonej
// pojawi sie potrzeba uzywania extern templates, zeby wymusic jedna instancje.
template <typename Product>
class Factory {
public:
typedef std::list<CreatorBase<Product> *> RegisteredList;
typedef typename RegisteredList::iterator iterator;
// Dostep do singletonu.
static Factory &instance() {
static Factory object;
return object;
}
void add(CreatorBase<Product> * creator) {
mRegisteredList.push_back(creator);
}
iterator begin() {
return mRegisteredList.begin();
}
iterator end() {
return mRegisteredList.end();
}
private:
RegisteredList mRegisteredList;
// Prywatny konstruktor.
Factory() {};
// A to jest wylaczone.
Factory(const Factory &) = delete;
Factory &operator=(const Factory &) = delete;
};
// Konstruktor CreatorBase musi byc tutaj z tego samego powodu co u Ciebie.
// To mi sie troche nie podoba, ale chyba jednak nie ma w tym niczego zlego.
template <typename AbstractProduct>
CreatorBase<AbstractProduct>::CreatorBase() {
Factory<AbstractProduct>::instance().add(this);
}
// Ponizej jest w zasadzie skopiowany Twoj kod.
// Plik register.h
class RegisteredBase // od tej klasy pochodzi dużo różnych klas
{
public:
virtual ~RegisteredBase() {}
virtual void WhoAmI()const=0; // tylko do demonstracji że to działa poprawnie
};
// Typedef zeby korzystanie z fabryki bylo bardziej czytelne.
typedef Factory<RegisteredBase> Register;
// Plik A.h
class A:public RegisteredBase // jedna z tych "różnych klas
{
public:
A() {}
virtual void WhoAmI()const { std::cout<<"class A"<<std::endl; }
};
// Rejestracja podobna jak u Ciebie.
// Mozna to uprosisc uzywajac template aliases, ale na ideone to nie zadziala.
Creator<RegisteredBase, A> CreatorA;
// Plik B.h
class B:public RegisteredBase // jeszcze jedna z tych "różnych klas
{
public:
B() {}
virtual void WhoAmI()const { std::cout<<"class B"<<std::endl; }
};
Creator<RegisteredBase, B> CreatorB;
// Plik C.h
class C:public RegisteredBase // kolejna z tych "różnych klas
{
public:
C() {}
virtual void WhoAmI()const { std::cout<<"class C"<<std::endl; }
};
Creator<RegisteredBase, C> CreatorC;
// main jest taki jak Twoj, tylko juz wczesniej zmienilem formatowanie.
int main() {
std::list<RegisteredBase *> obj;
for(Register::iterator it = Register::instance().begin();
it != Register::instance().end();
++it) {
obj.push_back((*it)->create());
}
for(std::list<RegisteredBase *>::iterator it = obj.begin();
it != obj.end();
++it) {
(*it)->WhoAmI();
delete *it;
}
return 0;
}