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.
Défi
FacileConstruisons 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
Documentavec une méthode virtuelle puregenerate()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
createDocumentqui prend deux chaînes : un type de document ("report"ou"invoice") et un format ("pdf"ou"html"). Elle doit renvoyer unstd::unique_ptr<Document>pointant vers le document concret approprié. Renvoyeznullptrpour les combinaisons non valides.Créez ensuite une classe de fabrique abstraite appelée
DocumentFactoryavec deux méthodes virtuelles pures :createReport(): renvoie unstd::unique_ptr<Document>createInvoice(): renvoie 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 disposer d'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 d'eux, un par ligne.main.cpp: 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 à partir des entrées. Affichez le résultat de l'appel à
generate()sur celui-ci.Affichez ensuite une ligne vide.
Créez ensuite un
DocumentServiceavec la fabrique appropriée en fonction de l'entrée de format (utilisezPDFFactorypourpdfetHTMLFactorypourhtml). AppelezgenerateAllDocuments()pour montrer comment la fabrique abstraite crée une famille de documents associé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 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;
}
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 externesGénération et compilation en C++Fichiers d’en-tête et fichiers sourceEspaces de noms et portéeIntroduction à la POO en C++Classes et objetsLe pointeur « this »Méthodes (fonctions membres)Attributs (membres de données)Bases des constructeurs et destructeursRécapitulatif - Calculatrice simple4Propriétés de classe
Membres d’instance et statiquesAccesseurs et mutateursFonctions membres constMot-clé mutableMéthodes et variables statiquesFonctions et classes amiesRécapitulatif - Gestionnaire de compte bancaire7Héritage
Héritage de baseNiveaux d’accès de l’héritageOrdre d’appel des constructeurs et destructeursRedéfinition des méthodesFonctions virtuelles et VTableHéritage multipleHéritage virtuelRécapitulatif : hiérarchie des employés10Vue d’ensemble de la STL
Vue d’ensemble et philosophie de la STLConteneurs de la STLItérateursAlgorithmes de la STLFoncteurs et expressions lambdaRécapitulatif - fréquence des mots13Modèles de conception, partie 1
Introduction aux modèles de conceptionModèle SingletonFabrique et fabrique abstraiteModèle BuilderModèle ObserverModèle Strategy2Gestion de la mémoire
Mémoire de pile ou de tasPointeurs et référencesMémoire dynamique (new/delete)Pointeurs intelligents 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 de l’informationStruct vs classeClasses imbriquées et internesRécapitulatif - Système de gestion des dossiers étudiants8Polymorphisme
Polymorphisme à la compilation vs à l’exécutionSurcharge de fonctionsRetour sur les fonctions virtuellesFonctions virtuelles puresClasses abstraitesConception d’interfaces en C++Conversion dynamique et RTTIRécapitulatif - Calculateur de formes3Constructeurs et destructeurs
Constructeur par défautConstructeur paramétréConstructeur de copieConstructeur de déplacementListes d’initialisation des constructeursConstructeurs déléguésApprofondissement des destructeursRègle des trois / cinq / zéroRécapitulatif - Classe String6Surcharge des opérateurs
Introduction à la surcharge des 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 des templatesTemplates variadiquesBases de SFINAE et des traits de typesRécapitulatif - Conteneur génériqueEntraînez-vous par vous-même : Compilateur C++ en ligne