In order to understand the factor pattern and why it is used, we consider to implement a program. The program is described as follow: The program should give the user an ability to to choose among several avaialable shapes (through command line argument) and once choosen, it should accept the parameters of the chosen shape. When user enters the required information, the progrma should display the shape. Moreover, the program should store the displayed entry as well. All the stored shapes can be redrawn at later stage.
Below is a snippet of user interacting with the program:
0 Redraw
1 Circle
2 Rectangle
Select a Shape: 2
Enter Rectangle Data (left, top, width, height): 10 10 100 100
Draw Rectangle: 10 10 100 100
0 Redraw
1 Circle
2 Rectangle
Select a Shape: 1
Enter Circle Data (cx, cy, radius): 20 20 200
Draw Circle: 20 20 200
0 Redraw
1 Circle
2 Rectangle
Select a Shape: 0
Draw Rectangle: 10 10 100 100
Draw Circle: 20 20 200
#include "stdafx.h"
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Shape
{
public:
static map<int, Shape*> command_map;
static int nr_registered;
Shape(string & shape_name)
{
nr_registered++;
command_map[nr_registered] = this;
}
virtual void show(){
//Do nothing
}
virtual void take_input(){
// Do nothing
}
virtual void draw(){
// Do nothing
}
};
int Shape::nr_registered;
map<int, Shape*> Shape::command_map;
class ConsoleUI
{
public:
void show()
{
int command;
while (true){
cout << "Following shapes are supported" << endl;
cout << "0 Print all" << endl;
for (std::map<int, Shape*>::iterator it = Shape::command_map.begin(); it != Shape::command_map.end(); ++it){
cout << it->first << " ";
it->second->show();
}
cin >> command;
if (command == 0){
for (std::map<int, Shape*>::iterator it = Shape::command_map.begin(); it != Shape::command_map.end(); ++it){
it->second->draw();
}
}
else{
Shape::command_map[command]->take_input();
Shape::command_map[command]->draw();
}
}
}
};
int main()
{
ConsoleUI cui;
cui.show();
return 0;
}
//-----------------------------------------------------------------------------------
class Rectangle : public Shape
{
private:
double _x, _y, _height, _width;
string commandName;
public:
Rectangle(string shape_name) : Shape(shape_name)
{
commandName = shape_name;
}
string return_command(){
return commandName;
}
void take_input(){
double x, y, height, width;
cout << "Give input in (x,y,height,width)" << endl;
cin >> x >> y >> height >> width;
_x = x;
_y = y;
_height = height;
_width = width;
}
void draw(){
cout << "Drawing Rectangle" << endl;
cout << _x << " " << _y << " " << _height << " " << _width << endl;
}
void show(){
cout << commandName << endl;
}
};
Rectangle r("rect");
class Circle : public Shape
{
private:
double _x, _y, _radius;
string commandName;
public:
Circle(string shape_name) : Shape(shape_name)
{
commandName = shape_name;
}
string return_command(){
return commandName;
}
void take_input(){
double x, y, radius;
cout << "Give input in (x,y,radius)" << endl;
cin >> x >> y >> radius;
_x = x;
_y = y;
_radius = radius;
}
void draw(){
cout << "Drawing Circle" << endl;
cout << _x << " " << _y << " " << _radius << endl;
}
void show(){
cout << commandName << endl;
}
};
Circle ra("cir");
In the above implementation, we see that if user requests to draw circle several times, then the single object representing circle is overwritten. This is not we want. In such a case, factory pattern comes in handy.
If a client code wants object without knowing class name, then factory pattern is used. It helps in creating objects of a certain class as and when required.
Factory method can be implemented in four different way:
- Factory method
- Abstract Factory
- Prototype
- Builder
Below code is not coupled with shape, because of the Shape Factory. Shape Factory helps in Dependency Inversion as they aggregate all the shapes.
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
// Abstraction of shape
class Shape
{
public:
virtual void take_input() = 0;
virtual void draw() = 0;
};
// Dependency inversion for factory creators
class ShapeFactory{
public:
static vector<ShapeFactory*> factory_list;
// virtual keyword makes a function bind late
// "=0" is to make it pure virtual function, and create the VTABLE for all derived class function
// A pure virtual function is just an interface which has to be declared in derived classes.
virtual string getShapeName() = 0;
virtual Shape* createShape() = 0;
protected:
ShapeFactory(/*this*/)
{
factory_list.push_back(this);
}
};
vector<ShapeFactory*> ShapeFactory::factory_list;
class ConsoleUI
{
public:
void show()
{
vector<Shape*> all_shapes; // For saving the shapes
int choice;
while (true){
cout << "0 Draw all" << endl;
int index = 1;
// range-for - Iterator Pattern
for (ShapeFactory *sp : ShapeFactory::factory_list){
cout << index++ << " " << sp->getShapeName() << endl;
}
cout << "Select a shape" << endl;
cin >> choice;
if (choice == 0){
for (Shape* s : all_shapes){
s->draw();
}
}
else{
Shape *shape = ShapeFactory::factory_list[choice - 1]->createShape();
shape->take_input();
shape->draw();
all_shapes.push_back(shape);
}
cout << "-----------------------------" << endl;
}
}
};
int main()
{
ConsoleUI cui;
cui.show();
return 0;
}
//-----------------------------------------------------------------------------------
class Rectangle : public Shape
{
private:
double _x, _y, _height, _width;
public:
void take_input(){
double x, y, height, width;
cout << "Give input in (x,y,height,width)" << endl;
cin >> x >> y >> height >> width;
_x = x;
_y = y;
_height = height;
_width = width;
}
void draw(){
cout << "Drawing Rectangle" << endl;
cout << _x << " " << _y << " " << _height << " " << _width << endl;
}
};
class Circle : public Shape
{
private:
double _x, _y, _radius;
public:
void take_input(){
double x, y, radius;
cout << "Give input in (x,y,radius)" << endl;
cin >> x >> y >> radius;
_x = x;
_y = y;
_radius = radius;
}
void draw(){
cout << "Drawing Circle" << endl;
cout << _x << " " << _y << " " << _radius << endl;
}
};
class RectangleFactory : public ShapeFactory
{
public:
string getShapeName(){
return "rectangle";
}
Shape* createShape()
{
Rectangle *rect = new Rectangle;
return rect;
}
};
//No body cares if factory object is created only once, because it is
// required only once.
RectangleFactory rf;
class CircleFactory : public ShapeFactory
{
public:
string getShapeName(){
return "circle";
}
Shape* createShape()
{
Circle *rect = new Circle;
return rect;
}
};
CircleFactory cf;
In the above code, we observe several things.
- Factory pattern enable us to create object as and when required.
- With factory class abstraction and main class abstraction, multiple objects can be created without knowing name.
All the Class implementations (the derived class) can be implemented into an new file and compiled separately as shared library.
In the main program, these library can be loaded.