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.
Défi
FacileConstruisons 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
Documentavec une méthode virtuelle puregenerate()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 :
PDFReport—generate()retourne"Generating PDF Report"HTMLReport—generate()retourne"Generating HTML Report"PDFInvoice—generate()retourne"Generating PDF Invoice"HTMLInvoice—generate()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
createDocumentqui prend deux chaînes de caractères : un type de document ("report"ou"invoice") et un format ("pdf"ou"html"). Elle doit retourner unstd::unique_ptr<Document>pointant vers le document concret approprié. Retourneznullptrpour les combinaisons invalides.Ensuite, créez une classe de fabrique abstraite appelée
DocumentFactoryavec deux méthodes virtuelles pures :createReport()— retourne unstd::unique_ptr<Document>createInvoice()— retourne unstd::unique_ptr<Document>
Implémentez deux fabriques concrètes :
PDFFactory— créePDFReportetPDFInvoiceHTMLFactory— créeHTMLReportetHTMLInvoice
DocumentService.h: Créez un service qui utilise la fabrique abstraite.Définissez une classe
DocumentServicequi prend unstd::unique_ptr<DocumentFactory>dans son constructeur. Elle doit avoir une méthode appeléegenerateAllDocuments()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 :
- Un type de document (
reportouinvoice) - Un format (
pdfouhtml)
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
DocumentServiceavec la fabrique appropriée basée sur l'entrée du format (utilisezPDFFactorypourpdf,HTMLFactorypourhtml). AppelezgenerateAllDocuments()pour montrer comment la fabrique abstraite crée une famille de documents liés.- Un type de document (
Par exemple, avec les entrées report et pdf :
Generating PDF Report
Generating PDF Report
Generating PDF InvoiceAvec les entrées invoice et html :
Generating HTML Invoice
Generating HTML Report
Generating HTML InvoiceRemarquez 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;
}
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
1Fondamentaux de la POO
Fichiers externesBuild et Compilation C++Fichiers d'en-tête et Fichiers sourceEspaces de noms et PortéeIntroduction à la POO en C++Classes vs ObjetsLe pointeur 'this'Méthodes (Fonctions membres)Attributs (Membres de données)Bases des Ctors et DtorsRécapitulatif - Calculatrice simple4Propriétés de classe
Membres d'instance vs membres statiquesGetters et SettersFonctions membres constMot-clé mutableMéthodes et variables statiquesFonctions et classes amiesRécapitulatif - Gestionnaire de compte bancaire7Héritage
Héritage de baseNiveaux d'accès à l'héritageOrdre d'appel des Ctor et DtorRedéfinition de méthodesFonctions virtuelles et VTableHéritage multipleHéritage virtuelRécapitulatif - Hiérarchie des employés10Présentation de la STL
Présentation et philosophie de la STLConteneurs de la STLItérateursAlgorithmes de la STLFoncteurs et expressions lambdaRécapitulatif - Fréquence des mots13Patrons de conception, Partie 1
Introduction aux patrons de conceptionPatron SingletonFabrique & Fabrique abstraitePatron MonteurPatron ObservateurPatron Stratégie2Gestion de la mémoire
Mémoire Pile vs TasPointeurs et RéférencesMémoire dynamique (new/delete)Smart Pointers en C++RAII en C++Récapitulatif - Gestionnaire de tableaux dynamiques5Encapsulation
Spécificateurs d'accès en C++Spécificateurs d'accès en profondeurMasquage d'informationStruct vs ClassClasses imbriquées et internesRécapitulatif - Système de gestion d'étudiants8Polymorphisme
Polymorphisme : Compilation vs ExécutionSurcharge de fonctionsRetour sur les fonctions virtuellesFonctions virtuelles puresClasses abstraitesConception d'interfaces en C++Dynamic Casting & RTTIRécapitulatif - Calculateur de formes11Concepts avancés de la POO
Composition vs HéritageMixins via CRTPIdiome PimplEffacement de typeEnum Classes & Typage fortGestion des exceptions en POOHiérarchies d'exceptions personnalisées14Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositeRAII en tant que patron3Constructeurs et Destructeurs
Constructeur par défautConstructeur paramétréConstructeur de copieConstructeur de déplacementListes d'initialisation du constructeurConstructeurs déléguésAnalyse approfondie du destructeurRègle de trois / cinq / zéroRécapitulatif - Classe String6Surcharge d'opérateurs
Introduction à la surcharge d'opérateursSurcharge des opérateurs arithmétiquesSurcharge des opérateurs de comparaisonOpérateurs de fluxSurcharge de l'opérateur d'affectationSurcharge des opérateurs [] et ()Opérateurs de conversion de typeRécapitulatif - Classe Matrix9Templates
Templates de fonctionsTemplates de classesSpécialisation de templatesTemplates variadiquesBases de SFINAE & Type TraitsRécapitulatif - Conteneur générique