C++ Factory Method

Jay Shaw Oct 12, 2023
  1. Factory Method in C++
  2. Simple Constructor Class in C++
  3. Use Factory Method to the Constructor Class in C++
  4. Concrete Classes and Abstract Factory Methods in C++
C++ Factory Method

The factory method is an object creation design pattern in C++ used to create objects while hiding their composition so the user can use the interface without seeing any method call.

Factory Method in C++

Factories are virtual constructors that allow a programmer to design programs that let the user interact with a clean program interface. This means hiding object creation itself inside the parent class.

If a program has two classes, a parent class and a user sub-class, using the constructor will lead to the two classes being highly dependent on each other. Any change-induced inside the parent class will lead to subsequent changes in sub-classes.

Factories’ feature is the ability to state the objects at the start of the program and opens up the capability of addition of new objects, as all the required changes will be inflicted just inside the library class and not anywhere else.

Simple Constructor Class in C++

Code:

#include <iostream>
using namespace std;

// LIBRARY/PARENT(Wire_Sizes) CLASS WITH Two_mm and Four_mm sub-classes
class Wire_Sizes {
 public:
  virtual void Diameter() = 0;
};
class Two_mm : public Wire_Sizes {
 public:
  void Diameter() { cout << "This wire is 2mm in diameter" << endl; }
};
class Four_mm : public Wire_Sizes {
 public:
  void Diameter() { cout << "This wire is 4mm in diameter" << endl; }
};

// CLIENT(User) CLASS
// One thing to note here is that object creation takes place inside the User
// class, which can affect the whole program if changes are to be made to the
// parent class - like adding a new category of wire diameter.

// In this client class, adding a new type will mean adding a new category to
// the existing if-else ladder.
class User {
 public:
  User(int type) {
    // Client explicitly creates classes according to type
    if (type == 1)
      pDiameter = new Two_mm();
    else if (type == 2)
      pDiameter = new Four_mm();
    else
      pDiameter = NULL;
  }
  ~User() {
    if (pDiameter) {
      delete[] pDiameter;
      pDiameter = NULL;
    }
  }
  Wire_Sizes *getDiameter() { return pDiameter; }

 private:
  Wire_Sizes *pDiameter;
};

// MAIN FUNCTION
int main() {
  User *pClient = new User(2);
  Wire_Sizes *pDiameter = pClient->getDiameter();
  pDiameter->Diameter();
  return 0;
}

Output:

This wire is 4mm in diameter

Run Live Demo

The Wire_Sizes is the library or the parent class with two sub-classes, Two_mm and Four_mm, where method Diameter() is overloaded and returns a print statement when the method is called.

In the User class, the parameter type takes the passed value from the main() function and creates an object class that matches the return type. The ~User()(destructor) destroys the allocated resources and clears the pointer.

The main() function creates object *pClient while passing value 2 to it. This value will get passed to the User(client) class, which will create an object of type 2 and then calls the corresponding method of type 2 from the Wire_Sizes(parent) class.

This makes the program highly dependent on its sub-classes and makes the code-intensive. Factories are used to solve this problem.

Use Factory Method to the Constructor Class in C++

Code:

#include <iostream>
using namespace std;

// The three derived classes, Size_two_mm, Size_three_mm, and Size_four_mm,
// contains the printDiameter() method, which is overloaded in all the
// subclasses
enum Size { Size_two_mm, Size_three_mm, Size_four_mm };
class Wire_Sizes {
 public:
  virtual void printDiameter() = 0;
  static Wire_Sizes* Create(Size type);
};
class Twomm : public Wire_Sizes {
 public:
  void printDiameter() { cout << "This wire is 2mm in diameter" << endl; }
};
class Threemm : public Wire_Sizes {
 public:
  void printDiameter() { cout << "This wire is 3mm in diameter" << endl; }
};
class Fourmm : public Wire_Sizes {
 public:
  void printDiameter() { cout << "This wire is 4mm in diameter" << endl; }
};

Wire_Sizes* Wire_Sizes::Create(Size type) {
  if (type == Size_two_mm)
    return new Twomm();
  else if (type == Size_three_mm)
    return new Threemm();
  else if (type == Size_four_mm)
    return new Fourmm();
  else
    return NULL;
}

class user {
 public:
  user() {
    Size type = Size_three_mm;
    pDiameter = Wire_Sizes::Create(type);
  }
  ~user() {
    if (pDiameter) {
      delete[] pDiameter;
      pDiameter = NULL;
    }
  }
  Wire_Sizes* getDiameter() { return pDiameter; }

 private:
  Wire_Sizes* pDiameter;
};

int main() {
  user* pClient = new user();
  Wire_Sizes* pDiameter = pClient->getDiameter();
  pDiameter->printDiameter();
  return 0;
}

Output:

This wire is 3mm in diameter

Run Live Demo

Inside the Size enum data, initially type three objects used in the program.

The if-else condition is written inside a new constructor Create() just after the Wire_Sizes(library) class. Adding a new object is easier than changing the client class.

The constructor takes in a value using the parameter type and matches it inside the if-else ladder. The corresponding function is called for a positive match, and NULL is returned in case of a negative match.

The user class doesn’t explicitly create objects but passes type to the factory method Create(). The object Size_three_mm is passed on to type and the constructor class Create() is assigned to pDiameter using the assignment operator.

The ~user()(destructor) destroys the resource allocated at the end of the class and allocates NULL to the variable pDiameter. Inside constructor getDiameter, variable pDiameter is returned.

The main() method creates the user class’s object *pClient and this object is called pDiameter() method. The getDiameter() method returns the pDiameter variable, which has the value stored inside the type.

The syntax Wire_Sizes * pDiameter = pClient->getDiameter(); pass the values of getDiameter() method to pDiameter which stores NULL and printDiameter() method is called.

Concrete Classes and Abstract Factory Methods in C++

When a method or class is declared, it is known as an abstract class for its inability to return something, and when that method or class is defined, it is known as concrete. Concrete classes can be instantiated and called as per requirement inside a factory.

Code:

#include <iostream>
using namespace std;

// BASE CLASS
class Concrete_Example {
 public:
  virtual ~Concrete_Example() {}
  virtual std::string Operation() const = 0;
};
class ExampleProduct1 : public Concrete_Example {
 public:
  std::string Operation() const override {
    return "{Product 1 is instantiated}";
  }
};

class ExampleProduct2 : public Concrete_Example {
 public:
  std::string Operation() const override {
    return "{Product 2 is instantiated}";
  }
};

// CREATOR CLASS
class Create {
 public:
  virtual ~Create(){};
  virtual Concrete_Example* FactoryMethod() const = 0;
  std::string SomeOperation() const {
    Concrete_Example* concrete_Example = this->FactoryMethod();
    std::string result = "Client Code" + concrete_Example->Operation();
    delete concrete_Example;
    return result;
  }
};

class ExampleCreator1 : public Create {
 public:
  Concrete_Example* FactoryMethod() const override {
    return new ExampleProduct1();
  }
};

class ExampleCreator2 : public Create {
 public:
  Concrete_Example* FactoryMethod() const override {
    return new ExampleProduct2();
  }
};

// USER CLASS
void User(const Create& create) {
  std::cout << "User Method is called\n" << create.SomeOperation() << std::endl;
}

// MAIN FUNCTION
int main() {
  std::cout << "App: Launched with the ConcreteCreator1.\n";
  Create* create = new ExampleCreator1();
  User(*create);
  std::cout << std::endl;
  std::cout << "App: Launched with the ConcreteCreator2.\n";
  Create* create2 = new ExampleCreator2();
  User(*create2);

  delete create;
  delete create2;
  return 0;
}

Output:

App: Launched with the ConcreteCreator1.
User Method is called
Client Code{Product 1 is instantiated}

App: Launched with the ConcreteCreator2.
User Method is called
Client Code{Product 2 is instantiated}

Run Live Demo

In this example, two concrete classes will be created inside a factory class and how the factory calls classes will be observed. The Concrete_Example(base) class provides many implementations for the product and its interface.

Class Concrete_Example has two subclasses - ExampleProduct1 and ExampleProduct2, which contain the products that the user class wants to call. The following is the Create(creator) class with a specific implementation - Declaring the factory method will pass an object from a product class to the user class.

The sub-classes are created to return the object and implement the methods for that purpose. Although the class name is created, no new objects are created in this class or its sub-classes.

The main purpose of the Create class is to return the products from the factory method. The sub-classes can override the method and add new implementation to the product.

Inside the SomeOperation method, an object from the factory Concrete_Example method is created, and the object is used to implement changes to the product. It can be observed that the sub-classes inflict changes to the product by overriding the factory method.

The client code used here uses the class create instance and its subclasses to call methods, making it independent from creating objects. Following the setup or environment, the application chooses a creator type.

The main function uses classCreate to form an object of subclass ExampleCreator1(). Both the creator methods are called in this program using objects created from the Create class, and after implementation, all the created objects are destroyed.

Related Article - C++ Method