Menu
Coddy logo textTech

Fabrique et fabrique abstraite

Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy. Leçon 92 sur 104.

Le pattern Factory délègue la création des objets à une méthode ou une classe distincte, ce qui vous permet de créer des objets sans spécifier leur classe exacte. Cela est utile lorsque la logique de création est complexe ou lorsque vous souhaitez découpler le code client des implémentations concrètes.

Une fabrique simple utilise une méthode qui renvoie différents types dérivés en fonction de l’entrée :

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

// Fonction 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;
}

L’Abstract Factory va plus loin en créant des familles d’objets associés. Au lieu d’une seule méthode d’usine, vous disposez d’une interface d’usine comportant plusieurs méthodes de création :

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

// Fabrique abstraite
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>();
    }
};

Utilisez Factory lorsque vous avez besoin d’une création flexible d’objets, et Abstract Factory lorsque vous devez vous assurer que les objets associés fonctionnent ensemble de manière cohérente.

challenge icon

Défi

Facile

Construisons un système de génération de documents en utilisant les motifs Factory et Abstract Factory. Vous allez créer un système capable de générer différents types de documents (rapports et factures) dans différents formats de sortie (PDF et HTML), en montrant comment les fabriques découplent la création des objets du code client.

Vous allez organiser votre code dans quatre fichiers :

  • Document.h : définissez votre hiérarchie de produits de documents.

    Créez une classe de base abstraite Document avec une méthode virtuelle pure generate() qui renvoie une chaîne décrivant le document généré, ainsi qu'un destructeur virtuel.

    Créez ensuite quatre classes de documents concrètes :

    • PDFReport : generate() renvoie "Generating PDF Report"
    • HTMLReport : generate() renvoie "Generating HTML Report"
    • PDFInvoice : generate() renvoie "Generating PDF Invoice"
    • HTMLInvoice : generate() renvoie "Generating HTML Invoice"
  • DocumentFactory.h : implémentez à la fois une fonction de fabrique simple et une fabrique abstraite.

    Commencez par créer une fonction de fabrique simple appelée createDocument qui prend deux chaînes : un type de document ("report" ou "invoice") et un format ("pdf" ou "html"). Elle doit renvoyer un std::unique_ptr<Document> pointant vers le document concret approprié. Renvoyez nullptr pour les combinaisons non valides.

    Créez ensuite une classe de fabrique abstraite appelée DocumentFactory avec deux méthodes virtuelles pures :

    • createReport() : renvoie un std::unique_ptr<Document>
    • createInvoice() : renvoie un std::unique_ptr<Document>

    Implémentez deux fabriques concrètes :

    • PDFFactory : crée PDFReport et PDFInvoice
    • HTMLFactory : crée HTMLReport et HTMLInvoice
  • DocumentService.h : créez un service qui utilise la fabrique abstraite.

    Définissez une classe DocumentService qui prend un std::unique_ptr<DocumentFactory> dans son constructeur. Elle doit disposer d'une méthode appelée generateAllDocuments() qui utilise la fabrique pour créer à la fois un rapport et une facture, puis affiche le résultat de l'appel à generate() sur chacun d'eux, un par ligne.

  • main.cpp : montrez les deux approches de fabrique.

    Lisez deux entrées :

    1. Un type de document (report ou invoice)
    2. Un format (pdf ou html)

    Tout d'abord, utilisez la fonction de fabrique simple pour créer un document à partir des entrées. Affichez le résultat de l'appel à generate() sur celui-ci.

    Affichez ensuite une ligne vide.

    Créez ensuite un DocumentService avec la fabrique appropriée en fonction de l'entrée de format (utilisez PDFFactory pour pdf et HTMLFactory pour html). Appelez generateAllDocuments() pour montrer comment la fabrique abstraite crée une famille de documents associés.

Par exemple, avec les entrées report et pdf :

Generating PDF Report

Generating PDF Report
Generating PDF Invoice

Avec les entrées invoice et html :

Generating HTML Invoice

Generating HTML Report
Generating HTML Invoice

Remarquez comment la fabrique simple crée un seul document en fonction des deux paramètres, tandis que la fabrique abstraite garantit que tous les documents créés par un service partagent le même format. C'est le principal avantage d'Abstract Factory lorsque vous avez besoin de familles d'objets associés qui fonctionnent ensemble de manière cohérente.

Essayez vous-même

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

using namespace std;

int main() {
    // Lire les entrées
    string documentType;
    string format;
    cin >> documentType;
    cin >> format;
    
    // TODO: Utiliser la fonction factory simple pour créer un document
    // basé sur les entrées documentType et format
    // Afficher le résultat de l'appel à generate() sur celui-ci
    
    // Afficher une ligne vide
    cout << endl;
    
    // TODO: Créer un DocumentService avec la factory appropriée
    // basé sur l'entrée format (PDFFactory pour "pdf", HTMLFactory pour "html")
    // Appeler generateAllDocuments() pour démontrer l'abstract factory
    
    return 0;
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet

Entraînez-vous par vous-même : Compilateur C++ en ligne