Menu
Coddy logo textTech

Fabrique & Fabrique abstraite

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

Le patron Factory délègue la création d'objets à une méthode ou une classe distincte, vous permettant de créer des objets sans spécifier leur classe exacte. Ceci 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 de fabrique
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 apparentés. Au lieu d'une seule méthode de fabrique, vous disposez d'une interface de fabrique avec 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"; }
};

// Abstract Factory
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 d'objets flexible, et Abstract Factory lorsque vous devez vous assurer que les objets liés fonctionnent ensemble de manière cohérente.

challenge icon

Défi

Facile

Construisons un système de Générateur de Documents en utilisant les patrons de conception Factory (Fabrique) et Abstract Factory (Fabrique Abstraite). Vous allez créer un système capable de générer différents types de documents (rapports et factures) pour différents formats de sortie (PDF et HTML), démontrant ainsi comment les fabriques découplent la création d'objets du code client.

Vous organiserez votre code sur quatre fichiers :

  • Document.h : Définissez votre hiérarchie de produits documentaires.

    Créez une classe de base abstraite Document avec une méthode virtuelle pure generate() qui retourne une chaîne de caractères décrivant le document généré, et un destructeur virtuel.

    Ensuite, créez quatre classes de documents concrètes :

    • PDFReportgenerate() retourne "Generating PDF Report"
    • HTMLReportgenerate() retourne "Generating HTML Report"
    • PDFInvoicegenerate() retourne "Generating PDF Invoice"
    • HTMLInvoicegenerate() retourne "Generating HTML Invoice"
  • DocumentFactory.h : Implémentez à la fois une fonction de fabrique simple et une fabrique abstraite.

    Tout d'abord, créez une fonction de fabrique simple appelée createDocument qui prend deux chaînes de caractères : un type de document ("report" ou "invoice") et un format ("pdf" ou "html"). Elle doit retourner un std::unique_ptr<Document> pointant vers le document concret approprié. Retournez nullptr pour les combinaisons invalides.

    Ensuite, créez une classe de fabrique abstraite appelée DocumentFactory avec deux méthodes virtuelles pures :

    • createReport() — retourne un std::unique_ptr<Document>
    • createInvoice() — retourne 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 avoir 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, un par ligne.

  • main.cpp : Dé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 basé sur les entrées. Affichez le résultat de l'appel à generate() sur celui-ci.

    Ensuite, affichez une ligne vide.

    Ensuite, créez un DocumentService avec la fabrique appropriée basée sur l'entrée du format (utilisez PDFFactory pour pdf, HTMLFactory pour html). Appelez generateAllDocuments() pour montrer comment la fabrique abstraite crée une famille de documents lié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 document unique basé sur les 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 l'avantage clé de l'Abstract Factory lorsque vous avez besoin de familles d'objets liés qui fonctionnent ensemble de manière cohérente.

Aide-mémoire

Le pattern Factory (ou patron de méthode de fabrique) délègue la création d'objets à une méthode ou une classe distincte, vous permettant de créer des objets sans spécifier leur classe exacte. Cela découple le code client des implémentations concrètes.

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

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 de fabrique
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;
}

Le pattern Abstract Factory (ou patron de fabrique abstraite) crée des familles d'objets apparentés. Au lieu d'une seule méthode de fabrique, vous disposez d'une interface de fabrique avec 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 d'objets flexible. Utilisez Abstract Factory lorsque vous devez vous assurer que des objets apparentés fonctionnent ensemble de manière cohérente en tant que famille.

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 de fabrique 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 fabrique appropriée
    // basé sur l'entrée format (PDFFactory pour "pdf", HTMLFactory pour "html")
    // Appeler generateAllDocuments() pour démontrer la fabrique abstraite
    
    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