1
Up until now, I never really used the Factory pattern that often in C++. Recently, I found a use for it in a project I was working on and since I found it useful for my purposes, I thought I might share a tutorial on how the Factory pattern can be used in C++.
Factory
pattern
but as far as I understand the Factory
pattern,
it is pretty close if not exact.2
Basically a Factory consists of an interface class which is common to all of the implementation classes that the factory will create. Then you have the factory class which is usually a singleton class that spawns instances of these implementation classes.
3
So let us create a quick
interface class to start with. In this
example, I used IAnimal
:
class IAnimal
{
public:
virtual int GetNumberOfLegs() const = 0;
virtual void Speak() = 0;
virtual void Free() = 0;
};
Now for simplicity’s sake, I
used a typedef
to
define a type for the function that is used
by the implementation classes to create
instances of IAnimal
.
This typedef
is
also used in declaring the map that maps the
animal name to the function that creates
that particular type of animal. You can use
whatever calling convention you like, but
for this example, I chose __stdcall
.
typedef IAnimal* (__stdcall *CreateAnimalFn)(void);
4
Now come the implementation
classes. These are the classes that
implement the IAnimal
interface.
Here’re a few examples:
// IAnimal implementations
class Cat : public IAnimal
{
public:
int GetNumberOfLegs() const { return 4; }
void Speak() { cout << “Meow” << endl; }
void Free() { delete this; }
static IAnimal * __stdcall Create() { return new Cat(); }
};
class Dog : public IAnimal
{
public:
int GetNumberOfLegs() const { return 4; }
void Speak() { cout << “Woof” << endl; }
void Free() { delete this; }
static IAnimal * __stdcall Create() { return new Dog(); }
};
class Spider : public IAnimal // Yeah it isn’t really an animal…
{
public:
int GetNumberOfLegs() const { return 8; }
void Speak() { cout << endl; }
void Free() { delete this; }
static IAnimal * __stdcall Create() { return new Spider(); }
};
class Horse : public IAnimal
{
public:
int GetNumberOfLegs() const { return 4; }
void Speak() { cout << “A horse is a horse, of course, of course.” << endl; }
void Free() { delete this; }
static IAnimal * __stdcall Create() { return new Horse(); }
};
5
Now comes the Factory
class.
This is a singleton pattern
implementation--meaning only one instance of
the factory can ever be instantiated, no
more, no less.
// Factory for creating instances of IAnimal
class AnimalFactory
{
private:
AnimalFactory();
AnimalFactory(const AnimalFactory &) { }
AnimalFactory &operator=(const AnimalFactory &) { return *this; }
typedef map FactoryMap;
FactoryMap m_FactoryMap;
public:
~AnimalFactory() { m_FactoryMap.clear(); }
static AnimalFactory *Get()
{
static AnimalFactory instance;
return &instance;
}
void Register(const string &animalName, CreateAnimalFn pfnCreate);
IAnimal *CreateAnimal(const string &animalName);
};
6
Now we need to work out a few
definitions of the AnimalFactory
class.
Specifically the constructor, theRegister
,
and the CreateAnimal
functions.
Constructor
The constructor is where you
might consider registering your Factory
functions.
Though this doesn’t have to be done here,
I’ve done it here for the purposes of this
example. You could for instance register
your Factory
types
with the Factory
class
from somewhere else in the code.
/* Animal factory constructor.
Register the types of animals here.
*/
AnimalFactory::AnimalFactory()
{
Register(“Horse”, &Horse::Create);
Register(“Cat”, &Cat::Create);
Register(“Dog”, &Dog::Create);
Register(“Spider”, &Spider::Create);
}
Type Registration
Now let us implement the Register
function.
This function is pretty straightforward
since I used a std::map
to
hold the mapping between my string
(the
animal type) and the create
function.
void AnimalFactory::Register(const string &animalName, CreateAnimalFn pfnCreate)
{
m_FactoryMap[animalName] = pfnCreate;
}
Type Creation
And last but not least, the CreateAnimal
function.
This function accepts a string
parameter
which corresponds to the string
registered
in the AnimalFactory
constructor.
When this function receives “Horse
”
for example, it will return an instance of
the Horse
class,
which implements the IAnimal
interface.
IAnimal *AnimalFactory::CreateAnimal(const string &animalName)
{
FactoryMap::iterator it = m_FactoryMap.find(animalName);
if( it != m_FactoryMap.end() )
return it->second();
return NULL;
}
7
int main( int argc, char **argv )
{
IAnimal *pAnimal = NULL;
string animalName;
while( pAnimal == NULL )
{
cout << “Type the name of an animal or ‘q’ to quit: “;
cin >> animalName;
if( animalName == “q” )
break;
IAnimal *pAnimal = AnimalFactory::Get()->CreateAnimal(animalName);
if( pAnimal )
{
cout << “Your animal has ” << pAnimal->GetNumberOfLegs() << ” legs.” << endl;
cout << “Your animal says: “;
pAnimal->Speak();
}
else
{
cout << “That animal doesn’t exist in the farm! Choose another!” << endl;
}
if( pAnimal )
pAnimal->Free();
pAnimal = NULL;
animalName.clear();
}
return 0;
}