Factory Pattern
Concept Definition
Factory centralizes object creation behind a function or class. Instead of letting every caller know which concrete class to construct, the caller asks for an object by role. The returned object is usually handled through a base-class pointer such as std::unique_ptr<Notifier>.
Think of a restaurant counter. You order "tea" or "coffee"; you do not walk into the kitchen and build the drink yourself.
Why It Matters
CSE students often write long if/else blocks in main() to decide which derived class to create. That works for tiny programs, but it spreads construction rules across the codebase. A Factory keeps creation logic in one place, which makes new derived classes easier to add and test.
Factory also pairs naturally with abstraction. The caller depends on the base interface, while the factory knows the concrete implementation.
Syntax Block
std::unique_ptr<Base> makeObject(const std::string& kind) {
if (kind == "name") { // choose concrete type
return std::make_unique<Derived>(); // return as base pointer
}
throw std::invalid_argument("bad kind"); // reject unknown requests
}
Explained Code
Example: Notification Factory
#include <memory> // std::unique_ptr, std::make_unique
#include <stdexcept> // std::invalid_argument
#include <string> // std::string
class Notifier {
public:
virtual ~Notifier() = default; // allow safe polymorphic deletion
virtual std::string channel() const = 0; // common interface
};
class EmailNotifier : public Notifier {
public:
std::string channel() const override { return "email"; } // concrete behavior
};
class SmsNotifier : public Notifier {
public:
std::string channel() const override { return "sms"; } // concrete behavior
};
std::unique_ptr<Notifier> makeNotifier(const std::string& type) {
if (type == "email") { return std::make_unique<EmailNotifier>(); } // build email
if (type == "sms") { return std::make_unique<SmsNotifier>(); } // build sms
throw std::invalid_argument("unknown notifier type"); // fail clearly
}
The caller receives std::unique_ptr<Notifier>, so it can use the object without knowing the exact class. If you later add PushNotifier, most client code does not change.
Key Points / Rules
- Use Factory when object creation is repeated or conditional.
- Return a base type when callers should depend on abstraction.
- Prefer
std::unique_ptrfor exclusive ownership of created objects. - Keep validation inside the factory so unknown requests fail predictably.
- Do not hide simple constructors behind factories when there is no creation problem.
Common Mistakes
- Putting too much logic in the factory. A factory should create objects, not run the whole business workflow.
- Returning raw owning pointers. Returning
new EmailNotifiermakes ownership unclear and risks leaks. - Using Factory for every class. A direct constructor call is clearer when there is only one simple concrete type.
- Forgetting a virtual destructor. Base classes used through pointers should have a virtual destructor.
Quick Check
- Why does
makeNotifier()returnstd::unique_ptr<Notifier>instead ofEmailNotifier? - What code changes when you add a new concrete notifier type?
Viva Answer
Factory is a design pattern that centralizes object creation. It lets client code ask for an abstract role while the factory decides which concrete class to instantiate.