C++ - Design pattern - Factory method

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! laugh

Add new comment

Plain text

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.