Factory Design Pattern in C++
The Factory design pattern deals with the problem of creating objects without specifying the exact class of object that will be created. Instead of calling a constructor directly, a factory method is used to create the object.
This method is typically defined in an interface and implemented by concrete classes. The pattern delegates the responsibility of object instantiation to specialized methods, rather than directly creating objects with constructors.
There are variations such as Simple Factory, Factory Method, and Abstract Factory. At its core, the Factory pattern abstracts the instantiation logic using methods.
Importance for a C++ Developer
- Decoupling: Separates client code from object creation logic, reducing impact when adding new types.
- Flexibility: New object types can be introduced without modifying existing code.
- Centralized Object Creation: Changes to creation logic are handled in one place.
- Hide Complex Creation Logic: Encapsulates complex initialization steps.
- Dynamic Runtime Decisions: Enables runtime selection of object types.
- Better Resource Management: Helps manage memory and resources efficiently in C++.
- Consistent Object Initialization: Ensures all objects are properly initialized.
🧩 Factory Method – UML Elements (C++)
1) Product
- Name:
Product - Why? Defines a common interface for all objects the factory creates.
- Function: Declares operations that all concrete products must implement.
2) ConcreteProductA / ConcreteProductB
- Name:
ConcreteProductA,ConcreteProductB - Why? Provide actual implementations of the Product interface.
- Function: Implement behavior and represent specific objects created by factories.
3) Creator
- Name:
Creator - Why? Defines the factory method contract.
- Function:
- Declares
FactoryMethod() - May implement operations using created products
- Acts as abstraction between client and concrete products
- Declares
4) ConcreteCreatorA / ConcreteCreatorB
- Name:
ConcreteCreatorA,ConcreteCreatorB - Why? Determines which product gets created.
- Function:
- Overrides
FactoryMethod() - Returns specific products
- Encapsulates instantiation logic
- Overrides
5) FactoryMethod()
- Why? Defers object creation to subclasses.
- Function: Returns a
Productand enables polymorphic creation.
6) AnOperation()
- Why? Demonstrates real usage of the factory.
- Function: Calls
FactoryMethod()and uses the result.
7) Client
- Why? Uses the system without tight coupling.
- Function: Works with abstractions, not concrete classes.
🧠Big Picture
- Product = WHAT is created
- Creator = HOW it is requested
- ConcreteCreator = WHICH one gets created
- FactoryMethod = WHERE the decision happens
Class Creation Order
- Product
- ConcreteProduct
- Creator
- ConcreteCreator
1. Product.h
#ifndef PRODUCT_H
#define PRODUCT_H
#include <iostream>
class Product {
public:
virtual void use() = 0;
virtual ~Product() {}
};
#endif
2. ConcreteProduct.h
#ifndef CONCRETEPRODUCT_H
#define CONCRETEPRODUCT_H
#include "Product.h"
class ConcreteProductA : public Product {
public:
void use() override;
};
class ConcreteProductB : public Product {
public:
void use() override;
};
#endif
ConcreteProduct.cpp
#include "ConcreteProduct.h"
void ConcreteProductA::use() {
std::cout << "Using ConcreteProductA" << std::endl;
}
void ConcreteProductB::use() {
std::cout << "Using ConcreteProductB" << std::endl;
}
3. Creator.h
#ifndef CREATOR_H
#define CREATOR_H
#include "Product.h"
class Creator {
public:
virtual Product* factoryMethod() = 0;
virtual ~Creator() {}
};
#endif
4. ConcreteCreator.h
#ifndef CONCRETECREATOR_H
#define CONCRETECREATOR_H
#include "Creator.h"
#include "ConcreteProduct.h"
class ConcreteCreatorA : public Creator {
public:
Product* factoryMethod() override;
};
class ConcreteCreatorB : public Creator {
public:
Product* factoryMethod() override;
};
#endif
ConcreteCreator.cpp
#include "ConcreteCreator.h"
Product* ConcreteCreatorA::factoryMethod() {
return new ConcreteProductA();
}
Product* ConcreteCreatorB::factoryMethod() {
return new ConcreteProductB();
}
5. main.cpp
#include <iostream>
#include "ConcreteCreator.h"
int main() {
Creator* creatorA = new ConcreteCreatorA();
Product* productA = creatorA->factoryMethod();
productA->use();
Creator* creatorB = new ConcreteCreatorB();
Product* productB = creatorB->factoryMethod();
productB->use();
delete productA;
delete creatorA;
delete productB;
delete creatorB;
return 0;
}
Final Explanation
- Product: Defines the interface.
- Concrete Products: Provide implementations.
- Creator: Declares factory method.
- Concrete Creators: Instantiate specific products.
- Client: Uses factory without knowing concrete classes.
Key Takeaways
- Encapsulation: Client depends only on abstractions.
- Scalability: Easy to add new products.
- Decoupling: Reduces dependency on concrete classes.
S.W.O.T. Analysis of the Factory Method Pattern in C++
Strengths
- Encapsulation: Hides object creation logic.
- Extensibility: Easily add new object types.
- Polymorphism: Supports dynamic object creation.
Weaknesses
- Virtual Functions Overhead: Adds runtime cost.
- Code Proliferation: More classes required.
- Manual Memory Management: Risk of leaks.
Opportunities
- Game Development: Useful for dynamic entities.
- Plugin Frameworks: Enables extensibility.
- Cross-Platform: Supports portable designs.
Threats
- Performance Risks: Overuse may slow systems.
- Overengineering: Not always necessary.
- Modern Alternatives: Templates and
constexprmay replace it.

No comments:
Post a Comment