Wzorce projektowe (5)
Autor: Damian Chodorek • Opublikowany: 20 lipca 2015 • Ostatnia aktualizacja: 21 lipca 2015 • Kategoria: kursy, wzorce projektowe
Uogólniona fabryka obiektów.
W poprzedniej części, poznałeś wzorzec fabryki obiektów. W tej części dowiesz się jak wygląda uogólnienie tego wzorca przy pomocy szablonów klas.
Uogólnieniem powinien być szablon, który umożliwia wybranie:
AbstractProduct
– tzn abstrakcyjną klasę, po której dziedziczą wszystkie konkretne produkty,IdentifierType
– obiekt, który będzie pełnił rolę ID, na podstawie którego będą tworzone konkretne produkty,ProductCreator
– funkcja albo funktor specjalizowany do tworzenia obiektów jednego i tylko jednego typu,FactoryErrorPolicy
– wytyczna pozwalająca na dostosowanie obsługi błędów do wyróżnionych scenariuszy.
Szablon
template <class AbstractProduct,
typename IdentifierType,
ProductCreator = AbstractProduct*(*)(),
template <typename, class> class FactoryErrorPolicy>
class Factory: public FactoryErrorPolicy<IdentifierType, AbstractProduct>{
public:
bool Register(const IdentifierType& id, ProductCreator creator){
return associations.insert(AssocMap::value_type(id, creator)).second;
}
bool Unregister(const IdentifierType& id){
return associations.erase(id)==1;
}
AbstractProduct* CreateObject(const IdentifierType& id){
typename AssocMap::const_iterator i=associations.find(id);
if(i!=associations.end()){
return (i->second)();
}
return OnUnknownType(id);
}
private:
typedef std::map<IdentifierType, ProductCreator> AssocMap;
AssocMap associations;
};
// Klasa błędu
template< class IdentifierType, class ProductType>
class DefaultFactoryError
{
public:
class Exception: public std::exception
{
public:
Exception(const IdentifierType& uid): unknownId(uid){}
virtual const char* what(){
return "nieznany typ obiektu";
}
const IdentifierType& GetId(){
return unknownId;
}
private:
IdentifierType unknownId;
};
protected:
static ProductType* OnUnknownType(const IdentifierType& Id){
throw Exception(id);
}
};