Open In App

Factory Method Pattern | C++ Design Patterns

Last Updated : 13 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Factory Method Pattern provides an interface for creating objects but leaves the actual object instantiation to derived classes. This allows for flexibility in object creation and promotes loose coupling between the creator (client code) and the concrete products.

Real-World Example of the Factory Method in C++

Imagine you want to build different types of things, like toys. You have a general idea of how toys are made, but you want different people to make different kinds of toys

  • The Factory Method is like a plan for making toys, but it doesn’t specify exactly what kind of toy you’re making.
  • It lets you create a plan (a method) that says, This is how you make a toy, without saying which toy it is.
  • Other people (subclasses) can use your plan to make their own types of toys. They just have to follow your plan and fill in the details for their specific toy.
  • This way you can make various toys without knowing exactly which one you’re making. It also keeps things neat and organized because each type of toy has its own set of instructions (a class) to follow.

In simple terms, the Factory Method Pattern is like a recipe for making things, but it lets different chefs (subclasses) create their own unique versions of those things while sticking to the same basic cooking instructions (the Factory Method).

Core Components of the Factory Method Pattern in C++

Let’s break down the key participants of the Factory Method Pattern:

1. Creator (Abstract Creator)

  • Description: An abstract class or interface responsible for declaring the factory method, which returns an object of a product type. The Creator Class can also contain other method that rely on the factory method to create objects.
  • Purpose: Provides a common interface for creating objects, but the specific object creation is defereed to concrete creators.

2. Concrete Creator:

  • Description: Concrete subclasses of the Creator. Each concrete creator implements the factory method declared in the abstract creator, returning a specific type of product.
  • Purpose: Responsible for creating instances of concrete products, thus encapsulating the actual object creation logic.

3. Product(Abstract Product):

  • Description: The abstract class or interface for the objects the factory method creates. It defines the common interface that all products must implement.
  • Purpose: Specifies the interface that concrete products must adhere to, ensuring that they have a consistent set of methods.

4. Concrete Product:

  • Description: Concrete implementations of the Product interface. Each concrete product represents a distinct type of object.
  • Purpose: Defines the acutal objects that the factory method creates. Each concrete product has its own implementation of the methods specified in teh Product interface.

5. Client:

  • Description: The client code interacts with the Creator through the abstarct Creator class and relies on the factory method to create instances of products.
  • Purpose: Utilizes the factory method pattern to create objects without needing to know specific class of objects being created, promoting flexibility and decoupling between the client and product classes.

Implementation of the Factory Method Pattern in C++

Let’s implement the Factory Method Pattern in C++ step by step, explaining each part in detail. In this example, we’ll create a simple shape factory that produces different shapes (e.g., Circle and Square).

Step 1: Define the Abstract Product (Shape)

C++
// Abstract product class
class Shape {
public:
    virtual void draw() = 0;
    virtual ~Shape() {} // Virtual destructor for polymorphism
};

Here, we’ve defined an abstract class Shape with a pure virtual function draw(). This class represents the abstract product that all concrete products must inherit from.

Step 2: Define Concrete Products (Circle and Square)

C++
// Concrete product class - Circle
class Circle : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Circle" << std::endl;
    }
};

// Concrete product class - Square
class Square : public Shape {
public:
    void draw() override {
        std::cout << "Drawing a Square" << std::endl;
    }
};

Here, we have two concrete classes, Circle and Square, that inherits from the Shape abstract class. Each concrete product (Circle and Square) provides its implementation of the draw() method.

Step 3: Define the Abstract Creator

C++
// Abstract creator class
class ShapeFactory {
public:
    virtual Shape* createShape() = 0;
    virtual ~ShapeFactory() {} // Virtual destructor for polymorphism
};

The abstract creator class, ShapeFactory, declare a pure virtual function createShape(), which will be implemented by concrete creators to create specific shapes.

Step 4: Define Concrete Creators (CircleFactory and Square Factory)

C++
// Concrete creator class - CircleFactory
class CircleFactory : public ShapeFactory {
public:
    Shape* createShape() override {
        return new Circle();
    }
};

// Concrete creator class - SquareFactory
class SquareFactory : public ShapeFactory {
public:
    Shape* createShape() override {
        return new Square();
    }
};

In this step, we’ve created two concrete creator classes, CircleFactory and SquareFactory, which implement the createShape() method to create instances of Circle and Square, respectively.

Step 5: Client Code

Now, let’s create a client to use the Factory Method Pattern:

C++
int main() {
    ShapeFactory* circleFactory = new CircleFactory();
    ShapeFactory* squareFactory = new SquareFactory();

    Shape* circle = circleFactory->createShape();
    Shape* square = squareFactory->createShape();

    circle->draw(); // Output: Drawing a Circle
    square->draw(); // Output: Drawing a Square

    delete circleFactory;
    delete squareFactory;
    delete circle;
    delete square;

    return 0;
}

In this client code, we first create instances of the concrete creators (circleFactory and squareFactory) and then use them to create instances of concrete products (cirlce and square). Finally, we call the draw() method on these objects, which produces the expected output.

Below is the complete combined code for the Factory Method Pattern in C++:

C++
// Abstract product class
#include <bits/stdc++.h>
class Shape {
public:
    virtual void draw() = 0;
    virtual ~Shape() {
    } // Virtual destructor for polymorphism
};
// Concrete product class - Circle
class Circle : public Shape {
public:
    void draw() override
    {
        std::cout << "Drawing a Circle" << std::endl;
    }
};

// Concrete product class - Square
class Square : public Shape {
public:
    void draw() override
    {
        std::cout << "Drawing a Square" << std::endl;
    }
};
// Abstract creator class
class ShapeFactory {
public:
    virtual Shape* createShape() = 0;
    virtual ~ShapeFactory() {
    } // Virtual destructor for polymorphism
};
// Concrete creator class - CircleFactory
class CircleFactory : public ShapeFactory {
public:
    Shape* createShape() override { return new Circle(); }
};

// Concrete creator class - SquareFactory
class SquareFactory : public ShapeFactory {
public:
    Shape* createShape() override { return new Square(); }
};
int main()
{
    ShapeFactory* circleFactory = new CircleFactory();
    ShapeFactory* squareFactory = new SquareFactory();

    Shape* circle = circleFactory->createShape();
    Shape* square = squareFactory->createShape();

    circle->draw(); // Output: Drawing a Circle
    square->draw(); // Output: Drawing a Square

    delete circleFactory;
    delete squareFactory;
    delete circle;
    delete square;
  
      // Client code based on user-input
  
      /* cout << "Enter shape type (circle or square): ";
    string shapeType;
    cin >> shapeType;

    ShapeFactory* shapeFactory = nullptr;
    if (shapeType == "circle") {
        shapeFactory = new CircleFactory();
    } else if (shapeType == "square") {
        shapeFactory = new SquareFactory();
    } else {
        cout << "Invalid shape type entered." << endl;
        return 1;
    }

    Shape* shape = shapeFactory->createShape();
    shape->draw();

    delete shapeFactory;
    delete shape; */

    return 0;
}

Output
Drawing a Circle
Drawing a Square




This implementation demonstrates the Factory Method Pattern, where:

  • The abstract creator (ShapeFactory) defines the factory method (createShape())
  • Concrete creators (CircleFactory and SquareFactory) implement this method to create concrete prodcuts (Circle and Square).
  • The client code interacts with the abstract creator, creating products without needing to know their specific types.
  • This promotes flexibility and decoupling between the client and product classes.

Real-World Use Cases of the Factory Method Pattern in C++ Design Patterns

The Factory Method Pattern finds application in various real-wrold scenarios, such as:

  1. GUI Libraries: GUI frameworks often use this pattern for creating UI components like buttons, windows, and dialogs. Different operating systems may have different implementations for these components.
  2. Database Drivers: Database connectivity libraries may use the Factory Method Pattern to create specific database dirver objects depending on the type of database being used (e.g., MySQL, PostgreSQL).
  3. Game Development: In game development, this pattern is used to create different types of game objects, characters, or weapons.
  4. Plugin Systems: When building extensible software systems, the Factory Method Pattern can be used to create and manage plugin instances dynamically.

Advantages of the Factory Method Pattern in C++ Design Patterns

  • Flexibility: It allows you to add new product types or change the way objects are created without modifying existing client code.
  • Encapsulation: The creation logic is encapsualted withing the concrete creators, promoting information hiding and modularity.
  • Maintainability: The pattern enhances code maitainability by isolating object creation code.
  • Testing: You easily substitue different product types with mock objects for testing purposes.

Disadvantages of the Factory Method Pattern in C++ Design Patterns

  • Increased Complexity: Introduces more classes and potential tight coupling, making the codebase more complex.
  • Tight Coupling: Concrete creators may be tightly linked to specific products, making changes cumbersome.
  • Limited to One Product Family: Best suited for single product families; not ideal for handlng multiple families.
  • Runtime Overhead: Some languages may introduce minor runtime overhead.
  • Potential Misuse: Can overcomplicate code if used unnecessarily.

Conclusion

The Factory Method Pattern is a valuable tool in C++ for achieving flexible and extensible object creation mechanisms. By abstracting the creation process into separate factory methods, you can write more maintainable, modular and testable code. It is a fundamental patten to have in your arsenal when designing object-oriented systems, offering a solution to the often complex problem of object instantiation.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads