Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

Polymorphic factories

The static factory( ) member function in the previous example forces all the creation operations to be focused in one spot, so that s the only place you need to change the code. This is certainly a reasonable solution, as it nicely encapsulates the process of creating objects. However, GoF emphasizes that the reason for the Factory Method pattern is so that different types of factories can be derived from the basic factory. Factory Method is in fact a special type of polymorphic factory. Here is ShapeFactory1.cpp modified so the Factory Methods are in a separate class as virtual functions:

//: C10:ShapeFactory2.cpp
// Polymorphic Factory Methods.
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <stdexcept>
#include <cstddef>
#include "../purge.h"
using namespace std;
 
class Shape {
public:
virtual void draw() = 0;
virtual void erase() = 0;
virtual ~Shape() {}
};
 
class ShapeFactory {
virtual Shape* create() = 0;
static map<string, ShapeFactory*> factories;
public:
virtual ~ShapeFactory() {}
friend class ShapeFactoryInitializer;
class BadShapeCreation : public logic_error {
public:
BadShapeCreation(string type)
: logic_error("Cannot create type " + type) {}
};
static Shape*
createShape(const string& id) throw(BadShapeCreation) {
if(factories.find(id) != factories.end())
return factories[id]->create();
else
throw BadShapeCreation(id);
}
};
 
// Define the static object:
map<string, ShapeFactory*> ShapeFactory::factories;
 
class Circle : public Shape {
Circle() {} // Private constructor
friend class ShapeFactoryInitializer;
class Factory;
friend class Factory;
class Factory : public ShapeFactory {
public:
Shape* create() { return new Circle; }
friend class ShapeFactoryInitializer;
};
public:
void draw() { cout << "Circle::draw << endl; }
void erase() { cout << "Circle::erase << endl; }
~Circle() { cout << "Circle::~Circle << endl; }
};
 
class Square : public Shape {
Square() {}
friend class ShapeFactoryInitializer;
class Factory;
friend class Factory;
class Factory : public ShapeFactory {
public:
Shape* create() { return new Square; }
friend class ShapeFactoryInitializer;
};
public:
void draw() { cout << "Square::draw << endl; }
void erase() { cout << "Square::erase << endl; }
~Square() { cout << "Square::~Square << endl; }
};
 
// Singleton to initialize the ShapeFactory:
class ShapeFactoryInitializer {
static ShapeFactoryInitializer si;
ShapeFactoryInitializer() {
ShapeFactory::factories["Circle"]= new Circle::Factory;
ShapeFactory::factories["Square"]= new Square::Factory;
}
~ShapeFactoryInitializer() {
map<string, ShapeFactory*>::iterator it =
ShapeFactory::factories.begin();
while(it != ShapeFactory::factories.end())
delete it++->second;
}
};
 
// Static member definition:
ShapeFactoryInitializer ShapeFactoryInitializer::si;
 
char* sl[] = { "Circle", "Square", "Square",
"Circle", "Circle", "Circle", "Square" };
 
int main() {
vector<Shape*> shapes;
try {
for(size_t i = 0; i < sizeof sl / sizeof sl[0]; i++)
shapes.push_back(ShapeFactory::createShape(sl[i]));
} catch(ShapeFactory::BadShapeCreation e) {
cout << e.what() << endl;
return EXIT_FAILURE;
}
for(size_t i = 0; i < shapes.size(); i++) {
shapes[i]->draw();
shapes[i]->erase();
}
purge(shapes);
} ///:~
 

Now the Factory Method appears in its own class, ShapeFactory, as virtual create( ). This is a private member function, which means it cannot be called directly but can be overridden. The subclasses of Shape must each create their own subclasses of ShapeFactory and override the create( ) member function to create an object of their own type. These factories are private, so that they are only accessible from the main Factory Method. This way, all client code must go through the Factory Method in order to create objects.

The actual creation of shapes is performed by calling ShapeFactory::createShape( ), which is a static member function that uses the map in ShapeFactory to find the appropriate factory object based on an identifier that you pass it. The factory creates the shape object directly, but you could imagine a more complex problem where the appropriate factory object is returned and then used by the caller to create an object in a more sophisticated way. However, it seems that much of the time you don t need the intricacies of the polymorphic Factory Method, and a single static member function in the base class (as shown in ShapeFactory1.cpp) will work fine.

Notice that the ShapeFactory must be initialized by loading its map with factory objects, which takes place in the Singleton ShapeFactoryInitializer. So to add a new type to this design you must define the type, create a factory, and modify ShapeFactoryInitializer so that an instance of your factory is inserted in the map. This extra complexity again suggests the use of a static Factory Method if you don t need to create individual factory objects.

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire