C++ Abstract Factory 패턴

서로 연관된 객체 집합(제품군)을 일관성 있게 생성하는 Abstract Factory 패턴입니다. 다크/라이트 테마 UI 위젯 팩토리를 예시로 구현합니다.

Gist
#include <iostream>
#include <memory>
#include <string>

// ─────────────────────────────────────────────
// Abstract Product A: 버튼 인터페이스
// ─────────────────────────────────────────────
class Button {
public:
    virtual ~Button() = default;
    virtual void render() const = 0;
    virtual void onClick() const = 0;
};

// ─────────────────────────────────────────────
// Abstract Product B: 체크박스 인터페이스
// ─────────────────────────────────────────────
class Checkbox {
public:
    virtual ~Checkbox() = default;
    virtual void render() const = 0;
    virtual void toggle() = 0;
    virtual bool isChecked() const = 0;
};

// ─────────────────────────────────────────────
// Abstract Product C: 입력 필드 인터페이스
// ─────────────────────────────────────────────
class InputField {
public:
    virtual ~InputField() = default;
    virtual void render() const = 0;
    virtual void setValue(const std::string& val) = 0;
    virtual std::string getValue() const = 0;
};

// ─────────────────────────────────────────────
// ConcreteProduct (Light 테마): 버튼, 체크박스, 입력 필드
// ─────────────────────────────────────────────
class LightButton final : public Button {
public:
    void render()   const override { std::cout << "  [Light 버튼] 흰 배경 / 검은 글씨\n"; }
    void onClick()  const override { std::cout << "  [Light 버튼] 클릭 이벤트 발생\n"; }
};

class LightCheckbox final : public Checkbox {
public:
    void render()       const override { std::cout << "  [Light 체크박스] □ 상태: " << (checked_ ? "✓" : "✗") << "\n"; }
    void toggle()             override { checked_ = !checked_; }
    bool isChecked()    const override { return checked_; }
private:
    bool checked_{false};
};

class LightInputField final : public InputField {
public:
    void render()           const override { std::cout << "  [Light 입력창] 값: \"" << value_ << "\"\n"; }
    void setValue(const std::string& v)    override { value_ = v; }
    std::string getValue()  const override { return value_; }
private:
    std::string value_;
};

// ─────────────────────────────────────────────
// ConcreteProduct (Dark 테마): 버튼, 체크박스, 입력 필드
// ─────────────────────────────────────────────
class DarkButton final : public Button {
public:
    void render()   const override { std::cout << "  [Dark 버튼] 검은 배경 / 흰 글씨\n"; }
    void onClick()  const override { std::cout << "  [Dark 버튼] 클릭 이벤트 발생\n"; }
};

class DarkCheckbox final : public Checkbox {
public:
    void render()       const override { std::cout << "  [Dark 체크박스] ■ 상태: " << (checked_ ? "✓" : "✗") << "\n"; }
    void toggle()             override { checked_ = !checked_; }
    bool isChecked()    const override { return checked_; }
private:
    bool checked_{false};
};

class DarkInputField final : public InputField {
public:
    void render()           const override { std::cout << "  [Dark 입력창] 값: \"" << value_ << "\"\n"; }
    void setValue(const std::string& v)    override { value_ = v; }
    std::string getValue()  const override { return value_; }
private:
    std::string value_;
};

// ─────────────────────────────────────────────
// Abstract Factory: 제품군 생성 인터페이스
// ─────────────────────────────────────────────
class UIFactory {
public:
    virtual ~UIFactory() = default;
    virtual std::unique_ptr<Button>     createButton()     const = 0;
    virtual std::unique_ptr<Checkbox>   createCheckbox()   const = 0;
    virtual std::unique_ptr<InputField> createInputField() const = 0;
    virtual std::string themeName()                        const = 0;
};

// ─────────────────────────────────────────────
// ConcreteFactory: Light / Dark 테마 팩토리
// ─────────────────────────────────────────────
class LightThemeFactory final : public UIFactory {
public:
    std::unique_ptr<Button>     createButton()     const override { return std::make_unique<LightButton>(); }
    std::unique_ptr<Checkbox>   createCheckbox()   const override { return std::make_unique<LightCheckbox>(); }
    std::unique_ptr<InputField> createInputField() const override { return std::make_unique<LightInputField>(); }
    std::string themeName()                        const override { return "Light"; }
};

class DarkThemeFactory final : public UIFactory {
public:
    std::unique_ptr<Button>     createButton()     const override { return std::make_unique<DarkButton>(); }
    std::unique_ptr<Checkbox>   createCheckbox()   const override { return std::make_unique<DarkCheckbox>(); }
    std::unique_ptr<InputField> createInputField() const override { return std::make_unique<DarkInputField>(); }
    std::string themeName()                        const override { return "Dark"; }
};

// ─────────────────────────────────────────────
// Client: 팩토리 인터페이스만 의존 — 구체 타입 무관
// ─────────────────────────────────────────────
void renderLoginForm(const UIFactory& factory) {
    std::cout << "\n=== [" << factory.themeName() << " 테마] 로그인 폼 렌더링 ===\n";

    auto emailInput    = factory.createInputField();
    auto passwordInput = factory.createInputField();
    auto rememberMe    = factory.createCheckbox();
    auto loginBtn      = factory.createButton();

    emailInput->setValue("user@example.com");
    passwordInput->setValue("••••••••");
    rememberMe->toggle();  // 체크 상태로 변경

    emailInput->render();
    passwordInput->render();
    rememberMe->render();
    loginBtn->render();
    loginBtn->onClick();
}

// ─────────────────────────────────────────────
// 사용 예시
// ─────────────────────────────────────────────
int main() {
    // 런타임에 테마 선택 가능 — 클라이언트 코드 변경 불필요
    auto lightFactory = std::make_unique<LightThemeFactory>();
    auto darkFactory  = std::make_unique<DarkThemeFactory>();

    renderLoginForm(*lightFactory);
    renderLoginForm(*darkFactory);

    return 0;
}