팩토리 & 추상 팩토리
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를 사용하세요.
챌린지
쉬움Document Generator 시스템을 Factory 및 Abstract Factory 패턴을 사용하여 구축해 보겠습니다. 서로 다른 출력 형식(PDF 및 HTML)에 대해 다양한 문서 유형(보고서 및 청구서)을 생성할 수 있는 시스템을 만들고, 팩토리가 객체 생성을 클라이언트 코드와 어떻게 분리하는지 보여 줍니다.
코드를 네 개의 파일로 구성합니다.
Document.h: 문서 product 계층 구조를 정의합니다.순수 가상 메서드
generate()를 포함하는 추상 기본 classDocument를 만듭니다. 이 메서드는 생성된 문서를 설명하는 문자열을 반환하며, 가상 소멸자도 포함합니다.그런 다음 네 개의 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:PDFReport와PDFInvoice를 생성합니다.HTMLFactory:HTMLReport와HTMLInvoice를 생성합니다.
DocumentService.h: abstract factory를 사용하는 서비스를 만듭니다.생성자에서
std::unique_ptr<DocumentFactory>를 받는DocumentServiceclass를 정의합니다. 이 class에는 factory를 사용하여 report와 invoice를 모두 생성한 다음, 각각에 대해generate()를 호출한 결과를 한 줄에 하나씩 출력하는generateAllDocuments()라는 메서드가 있어야 합니다.main.cpp: 두 factory 접근 방식을 모두 시연합니다.두 개의 입력을 읽습니다.
- 문서 유형(
report또는invoice) - 형식(
pdf또는html)
먼저 simple factory function을 사용하여 입력에 따라 문서를 생성합니다. 해당 문서에서
generate()를 호출한 결과를 출력합니다.그런 다음 빈 줄을 출력합니다.
이어서 형식 입력에 따라 적절한 factory를 사용하여
DocumentService를 생성합니다(pdf에는PDFFactory를,html에는HTMLFactory를 사용합니다).generateAllDocuments()를 호출하여 abstract factory가 서로 관련된 문서 family를 생성하는 방식을 보여 줍니다.- 문서 유형(
예를 들어 입력이 report와 pdf인 경우:
Generating PDF Report
Generating PDF Report
Generating PDF Invoice입력이 invoice와 html인 경우:
Generating HTML Invoice
Generating HTML Report
Generating HTML Invoicesimple 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;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 C++ 컴파일러