Menu
Coddy logo textTech

Factory e Abstract Factory

Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy. Lição 92 de 104.

O padrão Factory delega a criação de objetos a um método ou classe separado, permitindo criar objetos sem especificar sua classe exata. Isso é útil quando a lógica de criação é complexa ou quando você deseja desacoplar o código cliente das implementações concretas.

Uma fábrica simples usa um método que retorna diferentes tipos derivados com base na entrada:

#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"; }
};

// Função de fábrica
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;
}

A Abstract Factory leva isso além, criando famílias de objetos relacionados. Em vez de um método de fábrica, você tem uma interface de fábrica com vários métodos de criação:

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"; }
};

// Fábrica Abstrata
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>();
    }
};

Use Factory quando precisar de uma criação flexível de objetos e Abstract Factory quando precisar garantir que objetos relacionados funcionem juntos de forma consistente.

challenge icon

Desafio

Fácil

Vamos criar um sistema de Gerador de Documentos usando os padrões Factory e Abstract Factory. Você criará um sistema capaz de gerar diferentes tipos de documentos (relatórios e faturas) para diferentes formatos de saída (PDF e HTML), demonstrando como as fábricas desacoplam a criação de objetos do código cliente.

Você organizará seu código em quatro arquivos:

  • Document.h: Defina a hierarquia de produtos de documentos.

    Crie uma classe base abstrata Document com um método virtual puro generate() que retorna uma string descrevendo o documento gerado, além de um destrutor virtual.

    Em seguida, crie quatro classes concretas de documentos:

    • PDFReport: generate() retorna "Generating PDF Report"
    • HTMLReport: generate() retorna "Generating HTML Report"
    • PDFInvoice: generate() retorna "Generating PDF Invoice"
    • HTMLInvoice: generate() retorna "Generating HTML Invoice"
  • DocumentFactory.h: Implemente tanto uma função de fábrica simples quanto uma fábrica abstrata.

    Primeiro, crie uma função de fábrica simples chamada createDocument que receba duas strings: um tipo de documento ("report" ou "invoice") e um formato ("pdf" ou "html"). Ela deve retornar um std::unique_ptr<Document> apontando para o documento concreto apropriado. Retorne nullptr para combinações inválidas.

    Em seguida, crie uma classe de fábrica abstrata chamada DocumentFactory com dois métodos virtuais puros:

    • createReport(): retorna um std::unique_ptr<Document>
    • createInvoice(): retorna um std::unique_ptr<Document>

    Implemente duas fábricas concretas:

    • PDFFactory: cria PDFReport e PDFInvoice
    • HTMLFactory: cria HTMLReport e HTMLInvoice
  • DocumentService.h: Crie um serviço que use a fábrica abstrata.

    Defina uma classe DocumentService que receba um std::unique_ptr<DocumentFactory> em seu construtor. Ela deve ter um método chamado generateAllDocuments() que use a fábrica para criar um relatório e uma fatura, e então imprima o resultado da chamada de generate() em cada um, um por linha.

  • main.cpp: Demonstre as duas abordagens de fábrica.

    Leia duas entradas:

    1. Um tipo de documento (report ou invoice)
    2. Um formato (pdf ou html)

    Primeiro, use a função de fábrica simples para criar um documento com base nas entradas. Imprima o resultado da chamada de generate() nele.

    Em seguida, imprima uma linha em branco.

    Depois, crie um DocumentService com a fábrica apropriada com base na entrada de formato (use PDFFactory para pdf, HTMLFactory para html). Chame generateAllDocuments() para mostrar como a fábrica abstrata cria uma família de documentos relacionados.

Por exemplo, com as entradas report e pdf:

Generating PDF Report

Generating PDF Report
Generating PDF Invoice

Com as entradas invoice e html:

Generating HTML Invoice

Generating HTML Report
Generating HTML Invoice

Observe como a fábrica simples cria um único documento com base em ambos os parâmetros, enquanto a fábrica abstrata garante que todos os documentos criados por um serviço compartilhem o mesmo formato. Esse é o principal benefício do Abstract Factory quando você precisa de famílias de objetos relacionados que funcionem juntas de maneira consistente.

Experimente você mesmo

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

using namespace std;

int main() {
    // Ler entradas
    string documentType;
    string format;
    cin >> documentType;
    cin >> format;
    
    // TODO: Use a função de fábrica simples para criar um documento
    // com base nas entradas documentType e format
    // Imprima o resultado de chamar generate() nele
    
    // Imprima uma linha em branco
    cout << endl;
    
    // TODO: Crie um DocumentService com a fábrica apropriada
    // com base na entrada format (PDFFactory para "pdf", HTMLFactory para "html")
    // Chame generateAllDocuments() para demonstrar a fábrica abstrata
    
    return 0;
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de C++ online