[2026] C++ Factory Pattern: Complete Guide | Encapsulating Object Creation & Extensibility

[2026] C++ Factory Pattern: Complete Guide | Encapsulating Object Creation & Extensibility

이 글의 핵심

C++ Factory pattern explained: encapsulate creation, Simple Factory vs Factory Method vs Abstract Factory, auto-registration, plugins, and production patterns—with examples and SEO-friendly keywords.

The Korean C++ series groups creational patterns in C++ creational patterns #19-1 and a broader sweep in design patterns overview #20-2. For the same ideas in other languages, see JavaScript design patterns and Python decorators (often used for factories and singleton-style wrappers).

What is the Factory pattern? Why use it?

Problem: duplicated creation logic and tight coupling

Problem: If client code depends directly on concrete classes, adding a new type forces you to change every client. 아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// Client code (bad)
// 실행 예제
std::unique_ptr<Logger> logger;
if (config == "console") {
    logger = std::make_unique<ConsoleLogger>();
} else if (config == "file") {
    logger = std::make_unique<FileLogger>();
} else if (config == "network") {
    logger = std::make_unique<NetworkLogger>();
}
// Adding a type requires editing every client

Solution: The Factory pattern encapsulates creation so clients depend on an interface, and the factory chooses the concrete type. 다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// Factory
// 타입 정의
class LoggerFactory {
public:
    static std::unique_ptr<Logger> create(const std::string& type) {
        if (type == "console") return std::make_unique<ConsoleLogger>();
        if (type == "file") return std::make_unique<FileLogger>();
        if (type == "network") return std::make_unique<NetworkLogger>();
        return nullptr;
    }
};
// Client code (good)
auto logger = LoggerFactory::create(config);
logger->log("Hello");
// New types: change the factory only

아래 코드는 mermaid를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

flowchart TD
    client[Client]
    factory["LoggerFactory create(type)"]
    console[ConsoleLogger]
    file[FileLogger]
    network[NetworkLogger]
    
    client --> factory
    factory --> console
    factory --> file
    factory --> network

Table of contents

  1. Simple Factory
  2. Factory Method
  3. Abstract Factory
  4. Auto-registration factory
  5. Common pitfalls and fixes
  6. Production patterns
  7. Full example: plugin system

1. Simple Factory

Basic structure

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <memory>
#include <string>
#include <iostream>
class Shape {
public:
    virtual void draw() const = 0;
    virtual ~Shape() = default;
};
class Circle : public Shape {
public:
    void draw() const override {
        std::cout << "Drawing Circle\n";
    }
};
class Rectangle : public Shape {
public:
    void draw() const override {
        std::cout << "Drawing Rectangle\n";
    }
};
class ShapeFactory {
public:
    static std::unique_ptr<Shape> create(const std::string& type) {
        if (type == "circle") {
            return std::make_unique<Circle>();
        } else if (type == "rectangle") {
            return std::make_unique<Rectangle>();
        }
        return nullptr;
    }
};
int main() {
    auto shape = ShapeFactory::create("circle");
    if (shape) {
        shape->draw();  // "Drawing Circle"
    }
}

2. Factory Method

Extend the factory via inheritance

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <memory>
#include <iostream>
class Document {
public:
    virtual void open() = 0;
    virtual ~Document() = default;
};
class PDFDocument : public Document {
public:
    void open() override {
        std::cout << "Opening PDF\n";
    }
};
class WordDocument : public Document {
public:
    void open() override {
        std::cout << "Opening Word\n";
    }
};
// Creator (Factory Method pattern)
class Application {
public:
    virtual std::unique_ptr<Document> createDocument() = 0;
    
    void newDocument() {
        auto doc = createDocument();
        doc->open();
    }
    
    virtual ~Application() = default;
};
class PDFApplication : public Application {
public:
    std::unique_ptr<Document> createDocument() override {
        return std::make_unique<PDFDocument>();
    }
};
class WordApplication : public Application {
public:
    std::unique_ptr<Document> createDocument() override {
        return std::make_unique<WordDocument>();
    }
};
int main() {
    std::unique_ptr<Application> app = std::make_unique<PDFApplication>();
    app->newDocument();  // "Opening PDF"
}

3. Abstract Factory

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <memory>
#include <iostream>
// Product family
class Button {
public:
    virtual void render() = 0;
    virtual ~Button() = default;
};
class Checkbox {
public:
    virtual void render() = 0;
    virtual ~Checkbox() = default;
};
// Windows products
class WindowsButton : public Button {
public:
    void render() override {
        std::cout << "Rendering Windows Button\n";
    }
};
class WindowsCheckbox : public Checkbox {
public:
    void render() override {
        std::cout << "Rendering Windows Checkbox\n";
    }
};
// Mac products
class MacButton : public Button {
public:
    void render() override {
        std::cout << "Rendering Mac Button\n";
    }
};
class MacCheckbox : public Checkbox {
public:
    void render() override {
        std::cout << "Rendering Mac Checkbox\n";
    }
};
// Abstract Factory
class GUIFactory {
public:
    virtual std::unique_ptr<Button> createButton() = 0;
    virtual std::unique_ptr<Checkbox> createCheckbox() = 0;
    virtual ~GUIFactory() = default;
};
class WindowsFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<WindowsButton>();
    }
    
    std::unique_ptr<Checkbox> createCheckbox() override {
        return std::make_unique<WindowsCheckbox>();
    }
};
class MacFactory : public GUIFactory {
public:
    std::unique_ptr<Button> createButton() override {
        return std::make_unique<MacButton>();
    }
    
    std::unique_ptr<Checkbox> createCheckbox() override {
        return std::make_unique<MacCheckbox>();
    }
};
int main() {
    std::unique_ptr<GUIFactory> factory;
    
#ifdef _WIN32
    factory = std::make_unique<WindowsFactory>();
#else
    factory = std::make_unique<MacFactory>();
#endif
    
    auto button = factory->createButton();
    auto checkbox = factory->createCheckbox();
    
    button->render();
    checkbox->render();
}

4. Auto-registration factory

Registration without macros

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 에러 처리를 통해 안정성을 확보합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <memory>
#include <string>
#include <map>
#include <functional>
#include <iostream>
class Product {
public:
    virtual void use() = 0;
    virtual ~Product() = default;
};
class ProductA : public Product {
public:
    void use() override {
        std::cout << "Using Product A\n";
    }
};
class ProductB : public Product {
public:
    void use() override {
        std::cout << "Using Product B\n";
    }
};
// Auto-registration factory
class ProductFactory {
public:
    using Creator = std::function<std::unique_ptr<Product>()>;
    
    static void registerProduct(const std::string& type, Creator creator) {
        registry()[type] = creator;
    }
    
    static std::unique_ptr<Product> create(const std::string& type) {
        auto it = registry().find(type);
        if (it != registry().end()) {
            return it->second();
        }
        return nullptr;
    }
    
private:
    static std::map<std::string, Creator>& registry() {
        static std::map<std::string, Creator> reg;
        return reg;
    }
};
// Auto-registration helper
template<typename T>
class AutoRegister {
public:
    AutoRegister(const std::string& type) {
        ProductFactory::registerProduct(type, [] {
            return std::make_unique<T>();
        });
    }
};
// Register at static initialization
static AutoRegister<ProductA> registerA("A");
static AutoRegister<ProductB> registerB("B");
int main() {
    auto product = ProductFactory::create("A");
    if (product) {
        product->use();  // "Using Product A"
    }
}

5. Common pitfalls and fixes

Issue 1: Missing nullptr checks

Symptom: Crash. Cause: The factory may return nullptr but callers do not check. 아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// Wrong: no nullptr check
auto product = Factory::create("unknown");
product->use();  // Crash: nullptr dereference
// Correct: check nullptr
auto product = Factory::create("unknown");
if (product) {
    product->use();
} else {
    std::cerr << "Unknown product type\n";
}

Issue 2: Memory leaks

Symptom: Leaks. Cause: Objects created with new are never deleted. 아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// Wrong: raw pointer
Product* Factory::create(const std::string& type) {
    return new ConcreteProduct();  // Who deletes?
}
// Correct: unique_ptr
std::unique_ptr<Product> Factory::create(const std::string& type) {
    return std::make_unique<ConcreteProduct>();
}

Issue 3: Poor extensibility

Symptom: Every new type requires editing the factory. Cause: Long if-else chains. 아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// Wrong: if-else chain
std::unique_ptr<Product> Factory::create(const std::string& type) {
    if (type == "A") return std::make_unique<ProductA>();
    if (type == "B") return std::make_unique<ProductB>();
    // Edit here for every new type
    return nullptr;
}
// Correct: registration-based factory (see example above)

6. Production patterns

Pattern 1: Parameterized factory

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <memory>
#include <string>
#include <iostream>
class Logger {
public:
    virtual void log(const std::string& msg) = 0;
    virtual ~Logger() = default;
};
class FileLogger : public Logger {
public:
    FileLogger(const std::string& path) : filepath(path) {}
    
    void log(const std::string& msg) override {
        std::cout << "[File:" << filepath << "] " << msg << '\n';
    }
    
private:
    std::string filepath;
};
class LoggerFactory {
public:
    static std::unique_ptr<Logger> createFileLogger(const std::string& path) {
        return std::make_unique<FileLogger>(path);
    }
};
int main() {
    auto logger = LoggerFactory::createFileLogger("/var/log/app.log");
    logger->log("Application started");
}

Pattern 2: Singleton factory

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

class Factory {
public:
    static Factory& instance() {
        static Factory inst;
        return inst;
    }
    
    std::unique_ptr<Product> create(const std::string& type) {
        auto it = creators.find(type);
        if (it != creators.end()) {
            return it->second();
        }
        return nullptr;
    }
    
    void registerCreator(const std::string& type, Creator creator) {
        creators[type] = creator;
    }
    
private:
    Factory() = default;
    std::map<std::string, Creator> creators;
};

7. Full example: plugin system

다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <memory>
#include <string>
#include <map>
#include <functional>
#include <iostream>
class Plugin {
public:
    virtual void execute() = 0;
    virtual std::string getName() const = 0;
    virtual ~Plugin() = default;
};
class PluginFactory {
public:
    using Creator = std::function<std::unique_ptr<Plugin>()>;
    
    static PluginFactory& instance() {
        static PluginFactory inst;
        return inst;
    }
    
    void registerPlugin(const std::string& name, Creator creator) {
        creators_[name] = creator;
    }
    
    std::unique_ptr<Plugin> create(const std::string& name) {
        auto it = creators_.find(name);
        if (it != creators_.end()) {
            return it->second();
        }
        std::cerr << "Plugin not found: " << name << '\n';
        return nullptr;
    }
    
    void listPlugins() const {
        std::cout << "Available plugins:\n";
        for (const auto& [name, _] : creators_) {
            std::cout << "  - " << name << '\n';
        }
    }
    
private:
    PluginFactory() = default;
    std::map<std::string, Creator> creators_;
};
// Auto-registration helper
template<typename T>
class PluginRegistrar {
public:
    PluginRegistrar(const std::string& name) {
        PluginFactory::instance().registerPlugin(name, [] {
            return std::make_unique<T>();
        });
    }
};
// Plugin implementations
class ImagePlugin : public Plugin {
public:
    void execute() override {
        std::cout << "Processing image...\n";
    }
    
    std::string getName() const override {
        return "ImagePlugin";
    }
};
class VideoPlugin : public Plugin {
public:
    void execute() override {
        std::cout << "Processing video...\n";
    }
    
    std::string getName() const override {
        return "VideoPlugin";
    }
};
// Auto-register
static PluginRegistrar<ImagePlugin> registerImage("image");
static PluginRegistrar<VideoPlugin> registerVideo("video");
int main() {
    PluginFactory::instance().listPlugins();
    
    auto plugin = PluginFactory::instance().create("image");
    if (plugin) {
        std::cout << "Loaded: " << plugin->getName() << '\n';
        plugin->execute();
    }
}

Output: 아래 코드는 code를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

Available plugins:
  - image
  - video
Loaded: ImagePlugin
Processing image...

Summary

PatternDescription
Simple FactoryStatic method creates objects
Factory MethodSubclasses extend creation
Abstract FactoryCreates families of related objects
Auto-registrationGlobals register types automatically
ProsEncapsulation, extensibility, dependency inversion
ConsMore classes, higher complexity
The Factory pattern encapsulates creation and is a core creational pattern for maintainable C++ code.

FAQ

Q1: When should I use the Factory pattern?

A: When creation is non-trivial, new types are added often, or clients must not depend on concrete classes.

Q2: Simple Factory vs Factory Method?

A: Simple Factory uses a static method and is straightforward; Factory Method uses inheritance for extension.

Q3: When is Abstract Factory appropriate?

A: When you must create families of related objects together (e.g. Windows UI vs Mac UI).

Q4: Benefits of auto-registration?

A: New types can avoid editing the factory; globals register themselves.

Q5: Downsides?

A: More classes and indirection increase complexity.

Q6: Learning resources?

A:


Practical tips

Debugging

  • Fix compiler warnings first; reproduce with a minimal test case.

Performance

  • Do not optimize without profiling; define measurable goals.

Code review

  • Check team conventions and common review feedback.

Production checklist

Before coding

  • Is this the right fix for the problem?
  • Can the team maintain it?
  • Does it meet performance needs?

While coding

  • Warnings cleared?
  • Edge cases handled?
  • Error handling appropriate?

At review

  • Intent clear?
  • Tests sufficient?
  • Documented where needed?

Keywords (SEO)

C++, factory pattern, creational patterns, design patterns, polymorphism, plugin factory, abstract factory.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3