The Factory method design pattern is a really helpful one and a great dive into the world of design patterns.
In our example we are going to use an interface and some concrete classes.
If by reading this you are still interested in the concept, let's see the Factory method design pattern in this tutorial.
First of all
In the following tutorial we are going to use an interface class called IShip that three other classes will inherit: ShipTiny, ShipNormal and ShipEnormous.
The FactoryShip class will have a static method (our factory method) called createShip().
And inside this createShip() method we will create our ships depending on the shipType parameter passed at createShip().
This parameter is of type enum with the name SHIP_TYPE that specifies which kind of ship we want to construct.
So the goal of the factory method design pattern is to hide the objects generation from the programmer.
It's a great help when you want to create an API for example.
And furthermore you will be able to add new classes of the same type (same methods from the interface) without changing everything in the code already written.
Only the new ones will be impacted.
So let's code a bit.
Code
FactoryShip.cpp
#include <memory>
#include "FactoryShip.h"
#include "ShipTiny.h"
#include "ShipNormal.h"
#include "ShipEnormous.h"
// Badprog.com
// ----------------------------------------------------------------------------
// CTOR
// ----------------------------------------------------------------------------
FactoryShip::FactoryShip() {
}
// ----------------------------------------------------------------------------
// DTOR
// ----------------------------------------------------------------------------
FactoryShip::~FactoryShip() {
}
// ----------------------------------------------------------------------------
// createShip
// ----------------------------------------------------------------------------
std::unique_ptr<IShip> FactoryShip::createShip(SHIP_TYPE shipType) {
switch(shipType) {
case SHIP_TINY: return std::make_unique<ShipTiny>();
case SHIP_NORMAL: return std::make_unique<ShipNormal>();
case SHIP_ENORMOUS: return std::make_unique<ShipEnormous>();
default: return std::make_unique<ShipNormal>();
}
}
FactoryShip.h
#ifndef __BADPROG_FACTORYSHIP_H__
#define __BADPROG_FACTORYSHIP_H__
#include <memory>
#include "IShip.h"
// Badprog.com
class FactoryShip {
public:
// enum
enum SHIP_TYPE { SHIP_TINY, SHIP_NORMAL, SHIP_ENORMOUS };
FactoryShip();
virtual ~FactoryShip();
static std::unique_ptr<IShip> createShip(SHIP_TYPE shipType);
};
#endif // __BADPROG_FACTORYSHIP_H__
IShip.h
#ifndef __BADPROG_ISHIP_H__
#define __BADPROG_ISHIP_H__
#include <iostream>
// Badprog.com
// ----------------------------------------------------------------------------
// ShipTiny
// ----------------------------------------------------------------------------
class IShip
{
public:
virtual ~IShip() {}
virtual const float getSize() const = 0;
virtual void setSize(float sizeNew) = 0;
virtual const float getSpeed() const = 0;
virtual void setSpeed(float speedNew) = 0;
protected:
float _size;
float _speed;
};
#endif // __BADPROG_ISHIP_H__
main.cpp
#include <memory>
#include "IShip.h"
#include "FactoryShip.h"
// Badprog.com
// ----------------------------------------------------------------------------
// Main
// ----------------------------------------------------------------------------
int main()
{
// init
std::unique_ptr<IShip> ship1 = FactoryShip::createShip(FactoryShip::SHIP_TINY);
std::unique_ptr<IShip> ship2 = FactoryShip::createShip(FactoryShip::SHIP_NORMAL);
std::unique_ptr<IShip> ship3 = FactoryShip::createShip(FactoryShip::SHIP_ENORMOUS);
// setting (data that should be retrieved from a file.txt for example)
ship1->setSize(10);
ship1->setSpeed(500);
ship2->setSize(100);
ship2->setSpeed(200);
ship3->setSize(600);
ship3->setSpeed(50);
// getting data
std::cout << "ship1 size = " << ship1->getSize() << std::endl;
std::cout << "ship1 speed = " << ship1->getSpeed() << std::endl;
std::cout << "ship2 size = " << ship2->getSize() << std::endl;
std::cout << "ship2 speed = " << ship2->getSpeed() << std::endl;
std::cout << "ship3 size = " << ship3->getSize() << std::endl;
std::cout << "ship3 speed = " << ship3->getSpeed() << std::endl;
return 0;
}
ShipEnormous.cpp
#include "ShipEnormous.h"
// Badprog.com
// ----------------------------------------------------------------------------
// CTOR
// ----------------------------------------------------------------------------
ShipEnormous::ShipEnormous() {
}
// ----------------------------------------------------------------------------
// DTOR
// ----------------------------------------------------------------------------
ShipEnormous::~ShipEnormous() {
}
// ----------------------------------------------------------------------------
// setSize
// ----------------------------------------------------------------------------
void ShipEnormous::setSize(float sizeNew) {
_size = sizeNew;
}
// ----------------------------------------------------------------------------
// getSize
// ----------------------------------------------------------------------------
const float ShipEnormous::getSize() const {
return _size;
}
// ----------------------------------------------------------------------------
// setSpeed
// ----------------------------------------------------------------------------
void ShipEnormous::setSpeed(float speedNew) {
_speed = speedNew;
}
// ----------------------------------------------------------------------------
// getSpeed
// ----------------------------------------------------------------------------
const float ShipEnormous::getSpeed() const {
return _speed;
}
ShipEnormous.h
#ifndef __BADPROG_SHIPENORMOUS_H__
#define __BADPROG_SHIPENORMOUS_H__
#include "IShip.h"
// Badprog.com
// ----------------------------------------------------------------------------
// ShipEnormous
// ----------------------------------------------------------------------------
class ShipEnormous : public IShip {
public:
ShipEnormous();
virtual ~ShipEnormous();
void setSize(float sizeNew);
const float getSize() const;
void setSpeed(float speedNew);
const float getSpeed() const;
};
#endif // __BADPROG_SHIPENORMOUS_H__
ShipNormal.cpp
#include "ShipNormal.h"
// Badprog.com
// ----------------------------------------------------------------------------
// CTOR
// ----------------------------------------------------------------------------
ShipNormal::ShipNormal() {
}
// ----------------------------------------------------------------------------
// DTOR
// ----------------------------------------------------------------------------
ShipNormal::~ShipNormal() {
}
// ----------------------------------------------------------------------------
// setSize
// ----------------------------------------------------------------------------
void ShipNormal::setSize(float sizeNew) {
_size = sizeNew;
}
// ----------------------------------------------------------------------------
// getSize
// ----------------------------------------------------------------------------
const float ShipNormal::getSize() const {
return _size;
}
// ----------------------------------------------------------------------------
// setSpeed
// ----------------------------------------------------------------------------
void ShipNormal::setSpeed(float speedNew) {
_speed = speedNew;
}
// ----------------------------------------------------------------------------
// getSpeed
// ----------------------------------------------------------------------------
const float ShipNormal::getSpeed() const {
return _speed;
}
ShipNormal.h
#ifndef __BADPROG_SHIPNORMAL_H__
#define __BADPROG_SHIPNORMAL_H__
#include "IShip.h"
// Badprog.com
// ----------------------------------------------------------------------------
// ShipNormal
// ----------------------------------------------------------------------------
class ShipNormal : public IShip {
public:
ShipNormal();
virtual ~ShipNormal();
void setSize(float sizeNew);
const float getSize() const;
void setSpeed(float speedNew);
const float getSpeed() const;
};
#endif // __BADPROG_SHIPNORMAL_H__
ShipTiny.cpp
#include "ShipTiny.h"
// Badprog.com
// ----------------------------------------------------------------------------
// CTOR
// ----------------------------------------------------------------------------
ShipTiny::ShipTiny() {
}
// ----------------------------------------------------------------------------
// DTOR
// ----------------------------------------------------------------------------
ShipTiny::~ShipTiny() {
}
// ----------------------------------------------------------------------------
// setSize
// ----------------------------------------------------------------------------
void ShipTiny::setSize(float sizeNew) {
_size = sizeNew;
}
// ----------------------------------------------------------------------------
// getSize
// ----------------------------------------------------------------------------
const float ShipTiny::getSize() const {
return _size;
}
// ----------------------------------------------------------------------------
// setSpeed
// ----------------------------------------------------------------------------
void ShipTiny::setSpeed(float speedNew) {
_speed = speedNew;
}
// ----------------------------------------------------------------------------
// getSpeed
// ----------------------------------------------------------------------------
const float ShipTiny::getSpeed() const {
return _speed;
}
ShipTiny.h
#ifndef __BADPROG_SHIPTINY_H__
#define __BADPROG_SHIPTINY_H__
#include "IShip.h"
// Badprog.com
// ----------------------------------------------------------------------------
// ShipTiny
// ----------------------------------------------------------------------------
class ShipTiny : public IShip {
public:
ShipTiny();
virtual ~ShipTiny();
void setSize(float sizeNew);
const float getSize() const;
void setSpeed(float speedNew);
const float getSpeed() const;
};
#endif // __BADPROG_SHIPTINY_H__
Compiling, linking and executing
g++ *.cpp -o go.exe -std=c++1y ; ./go.exe
Result
ship1 size = 10
ship1 speed = 500
ship2 size = 100
ship2 speed = 200
ship3 size = 600
ship3 speed = 50
Conclusion
The Factory method design pattern helps having an abstract vision of a project and it's a first step through the global architecture of a program.
Well done, you did it!
Add new comment