Back to C++
2025-12-219 min read

C++ Factory Method Design Pattern

Learn C++ Factory Method Design Pattern step by step with clear examples and exercises.

Title: Mastering the Factory Method Design Pattern in C++

Why This Matters

In software development, creating objects can be a complex task, especially when dealing with multiple classes that share similar functionality but differ in implementation details. The Factory Method design pattern provides a solution to this problem by defining an interface for creating objects and allowing subclasses to decide which concrete class to instantiate. This pattern is essential for writing scalable, maintainable, and extensible code, especially when dealing with large-scale applications.

Prerequisites

To understand the Factory Method design pattern in C++, you should be familiar with:

  1. Object-oriented programming concepts (inheritance, polymorphism, encapsulation, and abstraction)
  2. C++ classes and objects
  3. Inheritance and polymorphism
  4. Interfaces and abstract classes
  5. Basic C++ syntax and standard library
  6. Understanding the concept of object creation and lifecycle management
  7. Familiarity with design patterns (creational, structural, and behavioral)

Core Concept

The Factory Method design pattern is a creational design pattern that provides an interface for creating objects in a superclass, allowing subclasses to alter the type of objects that will be produced. The Factory Method defines a method that returns an object without specifying the exact class of the object that will be created. This allows clients to work with abstract products and let the factory decide which concrete product to instantiate at runtime.

Here's a simple example demonstrating the Factory Method design pattern:

#include <iostream>
using namespace std;

// Abstract Product (interface)
class Shape {
public:
virtual void draw() = 0;
};

// Concrete Products (implementations of the interface)
class Circle : public Shape {
public:
void draw() override {
cout << "Drawing a circle." << endl;
}
};

class Rectangle : public Shape {
public:
void draw() override {
cout << "Drawing a rectangle." << endl;
}
};

// Factory (abstract factory)
class ShapeFactory {
public:
virtual Shape* createShape() = 0;
};

// Concrete Factories (implementations of the factory interface)
class CircleFactory : public ShapeFactory {
public:
Shape* createShape() override {
return new Circle();
}
};

class RectangleFactory : public ShapeFactory {
public:
Shape* createShape() override {
return new Rectangle();
}
};

// Client (uses the factory to create shapes)
int main() {
ShapeFactory* shapeFactory = new CircleFactory();
Shape* shape = shapeFactory->createShape();
shape->draw();

delete shapeFactory;
return 0;
}

In this example, we have an abstract product Shape, which is an interface for drawing shapes. We also have two concrete products: Circle and Rectangle. The Factory Method pattern is implemented using the ShapeFactory class, which provides a method called createShape() that returns a new shape object without specifying its exact type.

In our example, we have two concrete factories: CircleFactory and RectangleFactory, each of which creates either a Circle or a Rectangle. The client code uses the factory to create shapes and calls their draw() method. This way, the client is decoupled from the concrete product classes and can easily switch between different implementations by using different factories.

Factory Method vs Abstract Factory

The Factory Method pattern is a specific type of creational design pattern that creates objects without specifying their exact class. On the other hand, the Abstract Factory pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. The key difference lies in the scope of object creation: Factory Method focuses on creating single objects, while Abstract Factory deals with families of objects.

Factories and Singletons

It is possible to use factories with singleton objects by having the factory method return a single instance of the object instead of creating a new one each time it is called. This ensures that only one instance of the object exists across the entire application, which can be useful in scenarios where you want to centralize object creation and manage their lifecycle.

Worked Example

Let's consider a more complex example where we have multiple shapes that require different parameters for construction. We will create a ShapeFactory class with a method called createShape(int sides, int radius), which returns a new shape object based on the provided parameters:

#include <iostream>
#include <memory>
using namespace std;

// Abstract Product (interface)
class Shape {
public:
virtual void draw() = 0;
};

// Concrete Products (implementations of the interface)
class Circle : public Shape {
private:
int radius;
public:
Circle(int r) : radius(r) {}
void draw() override {
cout << "Drawing a circle with radius " << radius << "." << endl;
}
};

class Square : public Shape {
private:
int sideLength;
public:
Square(int s) : sideLength(s) {}
void draw() override {
cout << "Drawing a square with side length " << sideLength << "." << endl;
}
};

class Polygon : public Shape {
private:
int numSides, sideLength;
public:
Polygon(int n, int s) : numSides(n), sideLength(s) {}
void draw() override {
cout << "Drawing a polygon with " << numSides << " sides and side length " << sideLength << "." << endl;
}
};

// Factory (abstract factory)
class ShapeFactory {
public:
virtual shared_ptr<Shape> createShape(int sides, int radius = 0, int sideLength = 0) = 0;
};

// Concrete Factories (implementations of the factory interface)
class CircleFactory : public ShapeFactory {
public:
shared_ptr<Shape> createShape(int, int r) override {
return make_shared<Circle>(r);
}
};

class SquareFactory : public ShapeFactory {
public:
shared_ptr<Shape> createShape(int s) override {
return make_shared<Square>(s);
}
};

class PolygonFactory : public ShapeFactory {
public:
shared_ptr<Shape> createShape(int n, int s) override {
return make_shared<Polygon>(n, s);
}
};

// Client (uses the factory to create shapes)
int main() {
ShapeFactory* factory = new CircleFactory();
shared_ptr<Shape> shape1 = factory->createShape(0, 5);
shape1->draw();

delete factory;
factory = new SquareFactory();
shared_ptr<Shape> shape2 = factory->createShape(3);
shape2->draw();

factory = new PolygonFactory();
shared_ptr<Shape> shape3 = factory->createShape(6, 4);
shape3->draw();

return 0;
}

In this example, we have a more complex ShapeFactory class that can create different types of shapes based on the provided parameters. The client code demonstrates how to use the factory to create and draw various shapes without being aware of their concrete implementations.

Common Mistakes

  1. Not following the single responsibility principle: When a Factory Method is responsible for both creating objects and managing their lifecycle, it can lead to tightly coupled code that violates the single responsibility principle. To avoid this mistake, separate the creation of objects from their management.
  2. Overuse of factory methods: While the Factory Method design pattern can help decouple client code from concrete product classes, overusing factory methods can make the code more complex and harder to understand. Use factory methods judiciously when needed.
  3. Not providing enough flexibility in the factory method interface: If the factory method interface does not provide enough flexibility for subclasses to create different types of objects, it may lead to a lack of extensibility in the system. Make sure that the factory method interface is flexible enough to accommodate new concrete product classes.
  4. Ignoring the need for factories: Sometimes developers might overlook the need for factory methods when creating object hierarchies and end up with tightly coupled code. Always consider whether factory methods can help decouple client code from concrete product classes and make the system more maintainable and extensible.
  5. Not handling exceptions properly: When using factory methods, it's essential to handle exceptions that might occur during object creation. Failure to do so can lead to unhandled exceptions and program crashes.
  6. Using factory methods instead of inheritance in some cases: In situations where the relationship between classes is strictly hierarchical (i.e., a subclass inherits all properties and behavior from its parent), using inheritance might be more appropriate than using factory methods. However, factory methods can still provide benefits such as decoupling and extensibility when dealing with complex or dynamic relationships between classes.
  7. Not considering the trade-offs: The Factory Method design pattern introduces an additional layer of abstraction, which can make the code more complex and harder to understand. It's essential to consider the trade-offs and determine whether the benefits (decoupling, extensibility, etc.) outweigh the costs when deciding whether to use this design pattern.

Practice Questions

  1. Implement a Factory Method pattern for creating different types of animals (e.g., Dog, Cat, Bird) with their unique characteristics (e.g., barking, meowing, singing).
  2. Modify the example provided in the Core Concept section to include a Triangle shape and update the factory methods accordingly.
  3. Implement a Factory Method pattern for creating different types of vehicles (e.g., Car, Motorcycle, Truck) with their unique characteristics (e.g., number of wheels, engine type).
  4. Create a Factory Method pattern for generating different types of mathematical functions (e.g., Linear, Quadratic, Exponential).
  5. Implement a Factory Method pattern for creating different types of data structures (e.g., Stack, Queue, LinkedList) with their unique characteristics (e.g., push, pop, enqueue, dequeue).
  6. Modify the example provided in the Worked Example section to include a Star shape and update the factory methods accordingly.
  7. Implement a Factory Method pattern for creating different types of musical instruments (e.g., Piano, Guitar, Drums) with their unique characteristics (e.g., playing notes, producing sound).
  8. Modify the example provided in the Core Concept section to include a StarFactory that creates different types of stars (e.g., Star1, Star2, Star3) based on user input.
  9. Implement a Factory Method pattern for creating different types of plants (e.g., Rose, Sunflower, Cactus) with their unique characteristics (e.g., growing conditions, blooming period).

FAQ

What is the difference between the Factory Method and Abstract Factory design patterns?

The Factory Method pattern provides an interface for creating objects without specifying their exact class, while the Abstract Factory pattern provides a way to create families of related or dependent objects without specifying their concrete classes. The key difference lies in the scope of object creation: Factory Method focuses on creating single objects, while Abstract Factory deals with families of objects.

Can I use the Factory Method pattern with singleton objects?

Yes, you can use the Factory Method pattern with singleton objects by having the factory method return a single instance of the object instead of creating a new one each time it is called. This ensures that only one instance of the object exists across the entire application, which can be useful in scenarios where you want to centralize object creation and manage their lifecycle.

How does the Factory Method design pattern relate to inheritance and polymorphism?

The Factory Method design pattern relies on inheritance and polymorphism by defining an interface (abstract product) and having concrete products implement this interface. The factory method uses polymorphism to return a concrete product without specifying its exact type.

Why is it important to separate the creation of objects from their management?

Separating the creation of objects from their management helps decouple client code from the concrete implementation details, making the system more maintainable and extensible. This separation allows you to change the way objects are created or managed without affecting the client code that uses them.

What are some common pitfalls to avoid when implementing the Factory Method design pattern?

Some common pitfalls include not following the single responsibility principle, overuse of factory methods, not providing enough flexibility in the factory method interface, ignoring the need for factories, and not handling exceptions properly.

When should I use the Factory Method design pattern instead of inheritance or composition?

The Factory Method design pattern can be a good choice when you want to decouple client code from concrete product classes, provide extensibility by allowing subclasses to alter the type of objects that will be created, and centralize object creation. Inheritance might be more appropriate if the relationship between classes is strictly hierarchical (i.e., a subclass inherits all properties and behavior from its parent). Composition can be used when you want to compose objects using existing classes without modifying them.

How does the Factory Method design pattern help with testing?

The Factory Method design pattern helps with testing by decoupling client code from concrete product classes, making it easier to test individual components in isolation. This allows you to write unit tests for each component and verify their behavior independently of other parts of the system.

  1. Can I use multiple factory
C++ Factory Method Design Pattern | C++ | XQA Learn