Menu
Coddy logo textTech

팩토리 & 추상 팩토리

Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 104개 중 92번째.

Factory 패턴은 객체 생성을 별도의 메서드나 class에 위임하여, 정확한 class를 지정하지 않고도 객체를 create할 수 있게 합니다. 이는 생성 로직이 복잡하거나 클라이언트 코드를 concrete 구현과 분리하려는 경우에 유용합니다.

간단한 팩토리는 입력에 따라 서로 다른 파생 타입을 반환하는 메서드를 사용합니다:

#include <iostream>
#include <memory>

class Button {
public:
    virtual void render() = 0;
    virtual ~Button() = default;
};

class WindowsButton : public Button {
public:
    void render() override { std::cout << "Windows button\n"; }
};

class MacButton : public Button {
public:
    void render() override { std::cout << "Mac button\n"; }
};

// 팩토리 함수
std::unique_ptr<Button> createButton(const std::string& os) {
    if (os == "windows") return std::make_unique<WindowsButton>();
    if (os == "mac") return std::make_unique<MacButton>();
    return nullptr;
}

Abstract Factory는 서로 관련된 객체군을 생성하여 이 개념을 한 단계 더 발전시킵니다. 하나의 팩토리 메서드 대신 여러 생성 메서드를 포함하는 팩토리 인터페이스를 사용합니다:

class Checkbox {
public:
    virtual void check() = 0;
    virtual ~Checkbox() = default;
};

class WindowsCheckbox : public Checkbox {
public:
    void check() override { std::cout << "Windows checkbox\n"; }
};

class MacCheckbox : public Checkbox {
public:
    void check() override { std::cout << "Mac checkbox\n"; }
};

// 추상 팩토리
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>();
    }
};

유연한 객체 생성이 필요할 때는 Factory를 사용하고, 관련 객체들이 일관되게 함께 작동하도록 보장해야 할 때는 Abstract Factory를 사용하세요.

challenge icon

챌린지

쉬움

Document Generator 시스템을 Factory 및 Abstract Factory 패턴을 사용하여 구축해 보겠습니다. 서로 다른 출력 형식(PDF 및 HTML)에 대해 다양한 문서 유형(보고서 및 청구서)을 생성할 수 있는 시스템을 만들고, 팩토리가 객체 생성을 클라이언트 코드와 어떻게 분리하는지 보여 줍니다.

코드를 네 개의 파일로 구성합니다.

  • Document.h: 문서 product 계층 구조를 정의합니다.

    순수 가상 메서드 generate()를 포함하는 추상 기본 class Document를 만듭니다. 이 메서드는 생성된 문서를 설명하는 문자열을 반환하며, 가상 소멸자도 포함합니다.

    그런 다음 네 개의 concrete 문서 class를 만듭니다.

    • PDFReport: generate()"Generating PDF Report"를 반환합니다.
    • HTMLReport: generate()"Generating HTML Report"를 반환합니다.
    • PDFInvoice: generate()"Generating PDF Invoice"를 반환합니다.
    • HTMLInvoice: generate()"Generating HTML Invoice"를 반환합니다.
  • DocumentFactory.h: simple factory function과 abstract factory를 모두 구현합니다.

    먼저 createDocument라는 simple factory function을 만듭니다. 이 함수는 두 개의 문자열을 받습니다. 하나는 문서 유형("report" 또는 "invoice")이고, 다른 하나는 형식("pdf" 또는 "html")입니다. 적절한 concrete 문서를 가리키는 std::unique_ptr<Document>를 반환해야 합니다. 유효하지 않은 조합에는 nullptr를 반환합니다.

    그런 다음 두 개의 순수 가상 메서드를 가진 DocumentFactory라는 abstract factory class를 만듭니다.

    • createReport(): std::unique_ptr<Document>를 반환합니다.
    • createInvoice(): std::unique_ptr<Document>를 반환합니다.

    두 개의 concrete factory를 구현합니다.

    • PDFFactory: PDFReportPDFInvoice를 생성합니다.
    • HTMLFactory: HTMLReportHTMLInvoice를 생성합니다.
  • DocumentService.h: abstract factory를 사용하는 서비스를 만듭니다.

    생성자에서 std::unique_ptr<DocumentFactory>를 받는 DocumentService class를 정의합니다. 이 class에는 factory를 사용하여 report와 invoice를 모두 생성한 다음, 각각에 대해 generate()를 호출한 결과를 한 줄에 하나씩 출력하는 generateAllDocuments()라는 메서드가 있어야 합니다.

  • main.cpp: 두 factory 접근 방식을 모두 시연합니다.

    두 개의 입력을 읽습니다.

    1. 문서 유형(report 또는 invoice)
    2. 형식(pdf 또는 html)

    먼저 simple factory function을 사용하여 입력에 따라 문서를 생성합니다. 해당 문서에서 generate()를 호출한 결과를 출력합니다.

    그런 다음 빈 줄을 출력합니다.

    이어서 형식 입력에 따라 적절한 factory를 사용하여 DocumentService를 생성합니다(pdf에는 PDFFactory를, html에는 HTMLFactory를 사용합니다). generateAllDocuments()를 호출하여 abstract factory가 서로 관련된 문서 family를 생성하는 방식을 보여 줍니다.

예를 들어 입력이 reportpdf인 경우:

Generating PDF Report

Generating PDF Report
Generating PDF Invoice

입력이 invoicehtml인 경우:

Generating HTML Invoice

Generating HTML Report
Generating HTML Invoice

simple factory는 두 매개변수를 모두 기준으로 단일 문서를 생성하는 반면, abstract factory는 서비스에서 생성되는 모든 문서가 동일한 형식을 공유하도록 보장한다는 점에 주목하세요. 함께 일관되게 동작하는 관련 객체 family가 필요할 때 이것이 Abstract Factory의 핵심적인 이점입니다.

직접 해보기

#include <iostream>
#include <string>
#include <memory>
#include "Document.h"
#include "DocumentFactory.h"
#include "DocumentService.h"

using namespace std;

int main() {
    // 입력 읽기
    string documentType;
    string format;
    cin >> documentType;
    cin >> format;
    
    // TODO: 간단한 팩토리 함수를 사용하여 문서 생성
    // documentType 및 format 입력을 기반으로
    // 이에 대해 generate()를 호출한 결과 출력
    
    // 빈 줄 출력
    cout << endl;
    
    // TODO: 적절한 팩토리로 DocumentService 생성
    // format 입력을 기반으로 ("pdf"의 경우 PDFFactory, "html"의 경우 HTMLFactory)
    // 추상 팩토리를 시연하기 위해 generateAllDocuments() 호출
    
    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 C++ 컴파일러