Abstract Factory

N

Nindi

5 Files
Singleton.h The Singleton

Factory.h The factory creating new objects. The
Base class of the hierachy stores a typelist
identifying the signature of the constructors to
be called in the hierachy by the Factory

StaticFactory Returning refernences to a static object .. typelist
as above.

Phactory An implementation of an Abstract Factory. Each derived class
in a hierachy stores a typelist in itself to identify
the signature
of the constructor it would like the factory to use.
The correct constructor
is called in each derived class by the factory

main.cpp a demonstration of the factories

(Heavy reliance on Boost)


---------------------------------------------------
<main.cpp>
#include<vector>
#include<iostream>
#include"Factory.h"
#include"Phactory.h"

using namespace std;

struct MyClassVoid
{
typedef boost::mpl::list<> Constructor_TypeList;
MyClassVoid()
{}
virtual void f()const=0;
virtual ~MyClassVoid()
{}
;
};
struct MyClassVoidDerived :public MyClassVoid
{
MyClassVoidDerived()
{}
virtual void f()const
{
cout << " I am in MyClassVoidDerived \n";
}
virtual ~MyClassVoidDerived()
{}
;
};

namespace
{
Registra<MyClassVoid,MyClassVoidDerived>
theRegistraVoid(std::string("MyClassVoidDerived"));
}

struct MyClassDouble
{
typedef boost::mpl::list<double> Constructor_TypeList;
typedef boost::mpl::list<double> variant_type_list;
MyClassDouble(double)
{}
virtual void f()
{
cout << " I am in MyClassDouble \n";
}
virtual ~MyClassDouble()
{}
;
};
struct MyClassDoubleDerived :public MyClassDouble
{
typedef boost::mpl::list<double> constructor_signature_typelist;
MyClassDoubleDerived(double x):MyClassDouble(x)
{}
virtual void f()
{
cout << " I am in MyClassDoubleDerived \n";
}
virtual ~MyClassDoubleDerived()
{}
;
};
namespace
{
Registra<MyClassDouble,MyClassDouble>
theRegistra(std::string("MyClassDouble"));
Registra<MyClassDouble,MyClassDoubleDerived>
theRegistraD(std::string("MyClassDoubleDerived"));
}

struct MyClassMultiple
{
typedef
boost::mpl::list said:
Constructor_TypeList;

MyClassMultiple(std::string,std::vector<double>,double,MyClassDoubleDerived)
{}
virtual void f()
{
cout << " I am in MyClassMultiple \n";
}
virtual ~MyClassMultiple()
{}
;
};

namespace
{
Registra<MyClassMultiple,MyClassMultiple>
theRegistraM(std::string("MyClassMultiple"));
StaticRegistra<MyClassMultiple,MyClassMultiple>
theStaticRegistraM(std::string("MyClassMultiple"),std::string("String"),
std::vector<double>(2),1.0,MyClassDoubleDerived(1.0));
}

struct Dummy
{}
;

struct Base
{
typedef boost::mpl::list<double,int,unsigned
long,std::string,std::vector<double>,float,Dummy> variant_type_list;
Base()
{}
virtual void f()const=0;
virtual ~Base()
{}
;
};
struct Derived :public Base
{
typedef boost::mpl::list said:
constructor_signature_typelist;
Derived(double x_,int n_,const std::string &s_,const
std::vector<double>&v_):
x(x_),n(n_),s(s_),v(v_)
{}
virtual void f()const
{
cout << "My Double is " << x << "\n"
<< "My int is " << n << "\n"
<< "My String is " << s << "\n"
<< "My Vector Size is " << v.size() << "\n";
}
private:
double x;
int n;
std::string s;
std::vector<double> v;
};
namespace
{
const char * theVarNames[]=
{"Double","Int","String","Vector"
};
PhRegistra<Base,Derived>
thePhRegistra(std::string("DerivedObject"),PARAM_NAMES(theVarNames));
}


int main()
{
char ch;

boost::shared_ptr said:
::instance().RetrieveObject("MyClassVoidDerived"));
thePtrVoid->f();


boost::shared_ptr said:
::instance().RetrieveObject("MyClassDoubleDerived",1.0));
thePtrDoubleDerived->f();

boost::shared_ptr said:
::instance().RetrieveObject("MyClassDouble",1.0));
thePtrDouble->f();

boost::shared_ptr said:
::instance().RetrieveObject("MyClassMultiple",std::string("String"),std::vector<double>(2),1.0,MyClassDoubleDerived(1.0)));
thePtrM->f();

boost::shared_ptr said:
::instance().RetrieveObject("MyClassMultiple"));
thePtrSM->f();

std::map<std::string,typename boost::make_variant_over<typename
Base::variant_type_list::type>::type> theMap;

theMap["Double"]=1.0;
theMap["Int"]=1;
theMap["String"]="hello";
theMap["Vector"]=std::vector<double>(10);

boost::shared_ptr said:
::instance().RetrieveObject("DerivedObject",theMap));
thePtrPhM->f();


cin >>ch;
}

-----------------------------------------------------------------------------------------------

<singleton.h>

#ifndef SINGLETON_HEADER_GUARD
#define SINGLETON_HEADER_GUARD
#include <boost/utility.hpp>

template<class Object>
struct Singleton :boost::noncopyable
{

static Object & instance()
{
static Object theObject;
return theObject;
}
virtual ~Singleton()
{}

}
;

#endif

---------------------------------------------------------------------------

<Factory.h>
#ifndef FACTORY_HEADER_GUARD
#define FACTORY_HEADER_GUARD

#include<string>
#include<map>

#include"Singleton.h"

#include<boost/shared_ptr.hpp>
#include<boost/mpl/size.hpp>
#include<boost/mpl/list.hpp>
#include<boost/mpl/at.hpp>

#include<boost/preprocessor/repetition.hpp>
#include<boost/preprocessor/arithmetic/sub.hpp>

#ifndef MAX_FACTORIES
#define MAX_FACTORIES 10
#endif

// One Registration object per class in a hireachy,
//this is the template blue print for the base classes of
// the registration objects

template
<
class BaseClass,
typename Key = std::string,
unsigned long = boost::mpl::size<typename
BaseClass::Constructor_TypeList>::valuestruct RegistraBase
{}
;

// This is the template blue print for the concrete classes of
// the registration objects

template
<
class BaseClass,
class Derived,
typename Key = std::string,
unsigned long n = boost::mpl::size<typename
BaseClass::Constructor_TypeList>::valuestruct Registra :public RegistraBase<BaseClass,Key,n>
{}
;

// This is the factory template blue print of the Factory class

template
<
class BaseClass,
typename Key = std::string ,
unsigned long n = boost::mpl::size<typename
BaseClass::Constructor_TypeList>::valueclass Factory
{}
;

//Helper Macros
#define PARAM(z,Nb,data) typename boost::mpl::at_c<typename
BaseClass::Constructor_TypeList,Nb>::type P##Nb

#define REGISTRABASE(z,Nb,data)\
template<class BaseClass,typename Key> struct
RegistraBase<BaseClass,Key,Nb> { \
virtual boost::shared_ptr<BaseClass>
RetrieveObject(BOOST_PP_ENUM(Nb,PARAM,~))const=0;\
};

BOOST_PP_REPEAT(MAX_FACTORIES,REGISTRABASE,~)


#define FACTORY(z,Nb,data)\
template\
<\
class BaseClass,\
typename Key\
class Factory<BaseClass,Key,Nb> {\
public: \
bool Register(const Key & theKey,RegistraBase<BaseClass,Key,Nb>
*theRegistra){ \
return
theInnerMap.insert(InnerMap::value_type(theKey,theRegistra)).second; \
}\
\
boost::shared_ptr<BaseClass> RetrieveObject(const Key &id
BOOST_PP_COMMA_IF(Nb) BOOST_PP_ENUM(Nb,PARAM,~))const {\
InnerMapIterator theIterator (theInnerMap.find(id));\
if(theIterator==theInnerMap.end())return
boost::shared_ptr<BaseClass>(static_cast<BaseClass *>(0)); \
return theIterator->second->RetrieveObject(
BOOST_PP_ENUM_PARAMS(Nb,P));\
}\
private:\
typedef typename std::map<Key,RegistraBase<BaseClass,Key,Nb> *>
InnerMap;\
typedef typename std::map<Key,RegistraBase<BaseClass,Key,Nb>
*>::const_iterator InnerMapIterator;\
std::map<Key,RegistraBase<BaseClass,Key,Nb> *> theInnerMap;\
};

BOOST_PP_REPEAT(MAX_FACTORIES,FACTORY,~)

// The macro defintions of the Registration Objects

#define REGISTRA(z,Nb,data) \
template<class BaseClass,class Derived,typename Key>\
struct Registra<BaseClass,Derived,Key,Nb>:public
RegistraBase said:
::instance().Register(theKey,this);}\
boost::shared_ptr<BaseClass>
RetrieveObject(BOOST_PP_ENUM(Nb,PARAM,~))const\
{return boost::shared_ptr<BaseClass>(new Derived(
BOOST_PP_ENUM_PARAMS(Nb,P)));}\
virtual ~Registra(){}\
};

BOOST_PP_REPEAT(MAX_FACTORIES,REGISTRA,~)

#undef MAX_FACTORIES
#undef PARAM
#undef REGISTRA
#undef REGISTRABASE
#undef FACTORY

#include"StaticFactory.h"

#endif

-----------------------------------------------------------------------------------
<StaticFactory.h>
#ifndef STATIC_FACTORY_HEADER_GUARD
#define STATIC_FACTORY_HEADER_GUARD
#include<string>
#include<map>

#include"Singleton.h"

#include<boost/shared_ptr.hpp>
#include<boost/mpl/size.hpp>
#include<boost/mpl/list.hpp>
#include<boost/mpl/at.hpp>

#include<boost/preprocessor/repetition.hpp>
#include<boost/preprocessor/arithmetic/sub.hpp>

#ifndef MAX_STATIC_FACTORIES
#define MAX_STATIC_FACTORIES 10
#endif


template
<
class BaseClass,
typename Key = std::stringstruct StaticRegistraBase
{
virtual boost::shared_ptr<BaseClass> RetrieveObject()const=0;
}
;

template
<
class BaseClass,
class Derived,
typename Key = std::string,
unsigned long n = boost::mpl::size<typename
BaseClass::Constructor_TypeList>::valuestruct StaticRegistra :public StaticRegistraBase<BaseClass,Key>
{}
;

template
<
class BaseClass,
typename Key=std::stringclass StaticFactory
{
public:
bool Register(const Key & theKey,StaticRegistraBase<BaseClass,Key>
*theRegistra)
{
return
theInnerMap.insert(InnerMap::value_type(theKey,theRegistra)).second;
}
boost::shared_ptr<BaseClass> RetrieveObject(const Key &id )const
{
InnerMapIterator theIterator (theInnerMap.find(id));
if(theIterator==theInnerMap.end())
return boost::shared_ptr<BaseClass>(static_cast<BaseClass
*>(0));
return theIterator->second->RetrieveObject();
}

private:
typedef typename std::map<Key,StaticRegistraBase<BaseClass,Key> *>
InnerMap;
typedef typename std::map<Key,StaticRegistraBase<BaseClass,Key>
*>::const_iterator InnerMapIterator;
std::map<Key,StaticRegistraBase<BaseClass,Key> *> theInnerMap;

};

//Helper Macros
#define PARAM(z,Nb,data) typename boost::mpl::at_c<typename
BaseClass::Constructor_TypeList,Nb>::type P##Nb

#define STATICREGISTRA(z,Nb,data) template<class BaseClass,class
Derived,typename Key>\
struct StaticRegistra<BaseClass,Derived,Key, Nb >:public
StaticRegistraBase<BaseClass,Key> \
{\
StaticRegistra(const Key & theKey BOOST_PP_COMMA_IF(Nb)
BOOST_PP_ENUM(Nb,PARAM,~)): \
theObjectPtr(new Derived(BOOST_PP_ENUM_PARAMS(Nb,P)))\
{\
Singleton said:
::instance().Register(theKey,this); \
} \
boost::shared_ptr<BaseClass> RetrieveObject()const{return
theObjectPtr;}\
virtual ~StaticRegistra(){} \
private: \
boost::shared_ptr<BaseClass> theObjectPtr; \
};

BOOST_PP_REPEAT(MAX_STATIC_FACTORIES,STATICREGISTRA,~)

#undef MAX_STATIC_FACTORIES
#undef PARAM
#undef STATICREGISTRA

#endif

-------------------------------------------------------------------------------------------------

<Phactory.h>

#ifndef PHACTORY_HEADER_GUARD
#define PHACTORY_HEADER_GUARD


#include<string>
#include<map>
#include<cassert>

#include<boost/shared_ptr.hpp>
#include<boost/variant.hpp>
#include<boost/utility.hpp>
#include<boost/static_assert.hpp>

#include<boost/mpl/size.hpp>
#include<boost/mpl/list.hpp>
#include<boost/mpl/at.hpp>

#include<boost/preprocessor/repetition.hpp>


#ifndef MAX_PHACTORIES
#define MAX_PHACTORIES 10
#endif



template<unsigned long i>
struct unsigned_long
{
enum {value=i};
};

template<class BaseClass>
struct PhRegistraBase
{
typedef typename boost::make_variant_over<typename
BaseClass::variant_type_list::type>::type variant;
typedef std::map<std::string,variant> ParameterMap;

virtual boost::shared_ptr<BaseClass> RetrieveObject(const
std::string &theKey,const ParameterMap& theMap )const=0;
};

template<class BaseClass>
class Phactory
{
public:
typedef typename boost::make_variant_over<typename
BaseClass::variant_type_list::type>::type variant;
typedef std::map<std::string,variant> ParameterMap;
bool Register(const std::string &theKey, const
PhRegistraBase<BaseClass>* theRegistra)
{
return
theInnerMap.insert(InnerMap::value_type(theKey,theRegistra)).second;
}
boost::shared_ptr<BaseClass> RetrieveObject(const std::string &id,
const ParameterMap & theMap)const
{
InnerMapIterator theIterator (theInnerMap.find(id));
if(theIterator==theInnerMap.end())
return boost::shared_ptr<BaseClass>(static_cast<BaseClass
*>(0));
return theIterator->second->RetrieveObject(id,theMap);
}


private:
typedef typename std::map<std::string,const
PhRegistraBase<BaseClass> *> InnerMap;
typedef typename std::map<std::string,const
PhRegistraBase<BaseClass> *>::const_iterator InnerMapIterator;
std::map<std::string,const PhRegistraBase<BaseClass> *>
theInnerMap;
};


#define PARAM(z,Nb,data) boost::get<const boost::mpl::at_c<signature,
Nb >::type &>(theMap.find(theVarNames[Nb])->second)

#define INNER_RETRIVE_OBJECT(z,Nb,data)\
template said:
(const std::string &theKey,const ParameterMap& theMap)\
const{\
CheckMap(theMap);\
return boost::shared_ptr<BaseClass>(new DerivedClass(
BOOST_PP_ENUM(Nb,PARAM,~) ) \
);\
}



template
<
class BaseClass,
class DerivedClassclass PhRegistra:public PhRegistraBase<BaseClass>
{
public:
typedef typename DerivedClass::constructor_signature_typelist
signature;
typedef typename boost::make_variant_over<typename
BaseClass::variant_type_list::type>::type variant;
typedef std::map<std::string,variant> ParameterMap;

enum {ssize = boost::mpl::size<signature>::value};

template<unsigned long i>
PhRegistra(const std::string &theKey, const char
*theVariableNames[],const unsigned_long<i> *p=0)
{
BOOST_STATIC_ASSERT(i==ssize); // Must have ONE variable name
for each paramter of the constructor
for(unsigned long i(0);i<ssize;++i)
theVarNames=std::string(theVariableNames);
Singleton said:
::instance().Register(theKey,this);
}

boost::shared_ptr<BaseClass> RetrieveObject(const std::string
&theKey,const ParameterMap& theMap)const
{
return InnerRetrieveObject<ssize>(theKey,theMap);
}
template<int i>
boost::shared_ptr<BaseClass> InnerRetrieveObject(const std::string
&theKey,const ParameterMap&)const;

BOOST_PP_REPEAT(MAX_PHACTORIES,INNER_RETRIVE_OBJECT,~)

private:
void CheckMap(const ParameterMap& theMap)const
{
assert(theMap.size()==ssize);
for(unsigned long i(0);i<ssize;++i)
assert(theMap.find(theVarNames)!=theMap.end());
}
std::string theVarNames[ssize];
};

#define PARAM_NAMES(n) n ,
static_cast<unsigned_long<sizeof(n)/sizeof(char*)> *>(0)


#undef MAX_PHACTORIES
#undef PARAM
#undef INNER_RETRIVE_OBJECT


#endif
 
S

Salt_Peter

Nindi wrote:
<snipped lengthy code>

I stopped counting the syntax errors when i got to 10 (ran out of
fingers).
 
G

Gianni Mariani

Nindi said:
5 Files
Singleton.h The Singleton

Factory.h The factory creating new objects. The
Base class of the hierachy stores a typelist
identifying the signature of the constructors to
be called in the hierachy by the Factory

StaticFactory Returning refernences to a static object .. typelist
as above.

Phactory An implementation of an Abstract Factory. Each derived class
in a hierachy stores a typelist in itself to identify
the signature
of the constructor it would like the factory to use.
The correct constructor
is called in each derived class by the factory

main.cpp a demonstration of the factories

(Heavy reliance on Boost)


This is a link to a post I wrote not too long ago...
http://groups.google.com/group/comp.lang.c++/msg/225c720a0df450b0?hl=en&

Austria C++ has a generic factory system that also takes constructor
args as well as any key type and works with dynamic libraries.

One of the key issues was ensuring that the singleton was just that.
You need to put your singleton in a .cpp and link it exactly once (not
in any DLL's/.so's) and

Also, learn to use a documentation method. I know my docs suck and I
need to fix that but you need to add some docs...
http://austria.sourceforge.net/dox/html/group__GenericFactories.html

The unit test for the Austria factory does show how it is used. BTW,
the Austria unit test framework uses the Austria generic abstract factory...

So, what was your question anyway ?

G
 
N

Nindi

Gianni said:
This is a link to a post I wrote not too long ago...
http://groups.google.com/group/comp.lang.c++/msg/225c720a0df450b0?hl=en&

Austria C++ has a generic factory system that also takes constructor
args as well as any key type and works with dynamic libraries.

I will definitley take a look at that. Is it open source ? Are there
any issues with me just using it ?

One of the key issues was ensuring that the singleton was just that.
You need to put your singleton in a .cpp and link it exactly once (not
in any DLL's/.so's) and

This is something I am aware of already. I always define my static
instance function in a .cpp.
Also, learn to use a documentation method. I know my docs suck and I
need to fix that but you need to add some docs...
http://austria.sourceforge.net/dox/html/group__GenericFactories.html

Yes I know ... its very bad, I should.
The unit test for the Austria factory does show how it is used. BTW,
the Austria unit test framework uses the Austria generic abstract factory...

So, what was your question anyway ?

I just wanted some commenst like you have given just to see if I had
understodd some concepts correctly and implemented correctly. So thanks
 
G

Gianni Mariani

Nindi said:
Gianni Mariani wrote: ....
I will definitley take a look at that. Is it open source ? Are there
any issues with me just using it ?

It's GPL'd with the gcc exception.
This is something I am aware of already. I always define my static
instance function in a .cpp.

The Austria factory system goes a little further, it has a single
registry of registries in a single .cpp file in the Austria library.
Yes I know ... its very bad, I should.

You'd probably get more comments that way.
I just wanted some commenst like you have given just to see if I had
understodd some concepts correctly and implemented correctly. So thanks

K.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,037
Messages
2,570,371
Members
47,013
Latest member
JewellChes

Latest Threads

Top