Menu
Coddy logo textTech

Factory e Abstract Factory

Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 92 di 104.

Il pattern Factory delega la creazione degli oggetti a un metodo o a una classe separati, consentendoti di creare oggetti senza specificare la loro classe esatta. È utile quando la logica di creazione è complessa o quando vuoi disaccoppiare il codice client dalle implementazioni concrete.

Una factory semplice usa un metodo che restituisce tipi derivati diversi in base all'input:

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

// Funzione factory
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;
}

La Abstract Factory va oltre, creando famiglie di oggetti correlati. Invece di un solo metodo factory, hai un'interfaccia factory con più metodi di creazione:

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

// Fabbrica astratta
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>();
    }
};

Usa Factory quando hai bisogno di una creazione flessibile di oggetti e Abstract Factory quando devi assicurarti che gli oggetti correlati funzionino insieme in modo coerente.

challenge icon

Sfida

Facile

Costruiamo un sistema di generazione di documenti usando i pattern Factory e Abstract Factory. Creerai un sistema in grado di generare diversi tipi di documenti (report e fatture) in diversi formati di output (PDF e HTML), mostrando come le factory disaccoppiano la creazione degli oggetti dal codice client.

Organizzerai il codice in quattro file:

  • Document.h: definisci la gerarchia dei prodotti documentali.

    Crea una classe base astratta Document con un metodo virtuale puro generate() che restituisce una stringa che descrive il documento generato, e un distruttore virtuale.

    Crea poi quattro classi concrete per i documenti:

    • PDFReport: generate() restituisce "Generating PDF Report"
    • HTMLReport: generate() restituisce "Generating HTML Report"
    • PDFInvoice: generate() restituisce "Generating PDF Invoice"
    • HTMLInvoice: generate() restituisce "Generating HTML Invoice"
  • DocumentFactory.h: implementa sia una funzione factory semplice sia una factory astratta.

    Per prima cosa, crea una funzione factory semplice chiamata createDocument che accetta due stringhe: un tipo di documento ("report" o "invoice") e un formato ("pdf" o "html"). Dovrebbe restituire uno std::unique_ptr<Document> che punta al documento concreto appropriato. Restituisci nullptr per le combinazioni non valide.

    Crea poi una classe factory astratta chiamata DocumentFactory con due metodi virtuali puri:

    • createReport(): restituisce uno std::unique_ptr<Document>
    • createInvoice(): restituisce uno std::unique_ptr<Document>

    Implementa due factory concrete:

    • PDFFactory: crea PDFReport e PDFInvoice
    • HTMLFactory: crea HTMLReport e HTMLInvoice
  • DocumentService.h: crea un servizio che usa la factory astratta.

    Definisci una classe DocumentService che accetta uno std::unique_ptr<DocumentFactory> nel costruttore. Dovrebbe avere un metodo chiamato generateAllDocuments() che usa la factory per creare sia un report sia una fattura, quindi stampa il risultato della chiamata a generate() su ciascuno, uno per riga.

  • main.cpp: mostra entrambi gli approcci factory.

    Leggi due valori in ingresso:

    1. Un tipo di documento (report o invoice)
    2. Un formato (pdf o html)

    Per prima cosa, usa la funzione factory semplice per creare un documento in base ai valori inseriti. Stampa il risultato della chiamata a generate() su di esso.

    Stampa poi una riga vuota.

    Successivamente, crea un DocumentService con la factory appropriata in base al formato inserito (usa PDFFactory per pdf, HTMLFactory per html). Chiama generateAllDocuments() per mostrare come la factory astratta crea una famiglia di documenti correlati.

Ad esempio, con gli input report e pdf:

Generating PDF Report

Generating PDF Report
Generating PDF Invoice

Con gli input invoice e html:

Generating HTML Invoice

Generating HTML Report
Generating HTML Invoice

Nota come la factory semplice crei un singolo documento in base a entrambi i parametri, mentre la factory astratta garantisce che tutti i documenti creati da un servizio condividano lo stesso formato. Questo è il vantaggio principale di Abstract Factory quando hai bisogno di famiglie di oggetti correlati che funzionino insieme in modo coerente.

Provalo tu

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

using namespace std;

int main() {
    // Leggi gli input
    string documentType;
    string format;
    cin >> documentType;
    cin >> format;
    
    // TODO: Usa la funzione factory semplice per creare un documento
    // in base agli input documentType e format
    // Stampa il risultato della chiamata a generate() sul documento
    
    // Stampa una riga vuota
    cout << endl;
    
    // TODO: Crea un DocumentService con la factory appropriata
    // in base all'input format (PDFFactory per "pdf", HTMLFactory per "html")
    // Chiama generateAllDocuments() per mostrare il funzionamento della factory astratta
    
    return 0;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C++ online