Pattern Méthode Modèle
Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy. Leçon 99 sur 104.
Le patron Template Method définit le squelette d’un algorithme dans une classe de base, en permettant aux sous-classes de redéfinir des étapes spécifiques sans modifier la structure globale de l’algorithme. Contrairement à Strategy, qui remplace des algorithmes entiers, Template Method conserve l’algorithme fixe tout en permettant de personnaliser des étapes individuelles.
La classe de base implémente la méthode modèle (l’algorithme) et appelle des méthodes abstraites ou virtuelles que les sous-classes doivent fournir :
#include <iostream>
class DataProcessor {
public:
// Méthode template - définit le squelette de l'algorithme
void process() {
loadData();
processData();
saveResults();
}
virtual ~DataProcessor() = default;
protected:
virtual void loadData() = 0; // Doit être implémenté
virtual void processData() = 0; // Doit être implémenté
// Hook - redéfinition optionnelle avec comportement par défaut
virtual void saveResults() {
std::cout << "Saving to default location\n";
}
};
class CSVProcessor : public DataProcessor {
protected:
void loadData() override {
std::cout << "Loading CSV file\n";
}
void processData() override {
std::cout << "Parsing CSV data\n";
}
};
class JSONProcessor : public DataProcessor {
protected:
void loadData() override {
std::cout << "Loading JSON file\n";
}
void processData() override {
std::cout << "Parsing JSON data\n";
}
void saveResults() override {
std::cout << "Saving to cloud storage\n";
}
};
int main() {
CSVProcessor csv;
csv.process(); // Utilise saveResults par défaut
JSONProcessor json;
json.process(); // Utilise saveResults personnalisé
}La méthode process() est la méthode modèle : elle définit la séquence fixe des étapes. Les sous-classes implémentent loadData() et processData() différemment, mais l’ordre ne change jamais. La méthode saveResults() est un « hook » : elle possède une implémentation par défaut que les sous-classes peuvent éventuellement redéfinir.
Utilisez Template Method lorsque vous avez un algorithme comportant des étapes invariantes, mais que vous avez besoin de flexibilité pour certaines opérations, ou lorsque vous souhaitez éviter la duplication de code entre des classes similaires.
Défi
FacileConstruisons un système de génération de rapports utilisant le patron Template Method. Vous allez créer un framework dans lequel différents types de rapports (comme les rapports de ventes et les rapports d’inventaire) suivent le même processus de génération, mais chaque type de rapport personnalise certaines étapes. C’est un scénario parfait pour Template Method : le flux de travail global reste fixe tandis que les étapes individuelles varient.
Vous allez organiser votre code dans trois fichiers :
ReportGenerator.h: définir la classe de base abstraite avec la méthode modèle.Créez une classe
ReportGeneratorqui définit la structure de l’algorithme de génération de rapports. Votre méthode modèlegenerateReport()doit exécuter ces étapes dans l’ordre :gatherData(): virtuelle pure, doit être implémentée par les sous-classesformatReport(): virtuelle pure, doit être implémentée par les sous-classesaddHeader(): un hook avec un comportement par défaut qui affiche--- Report ---printReport(): virtuelle pure, doit être implémentée par les sous-classes
La méthode
addHeader()sert de hook que les sous-classes peuvent éventuellement redéfinir pour personnaliser l’en-tête.Reports.h: implémenter deux générateurs de rapports concrets.Créez une classe
SalesReportqui :gatherData()afficheGathering sales data from databaseformatReport()afficheFormatting sales figuresprintReport()afficheSales Total: $[amount], où amount est transmis au constructeur
Créez une classe
InventoryReportqui :gatherData()afficheScanning inventory recordsformatReport()afficheOrganizing inventory by categoryaddHeader()redéfinit le hook pour afficher=== Inventory Report ===printReport()afficheItems in stock: [count], où count est transmis au constructeur
Les deux classes doivent accepter leurs valeurs respectives (amount ou count) via leurs constructeurs.
main.cpp: démontrer le patron Template Method.Lisez deux entrées :
- Montant des ventes (entier)
- Nombre d’articles en inventaire (entier)
Créez un
SalesReportavec le montant des ventes et générez-le. Créez ensuite unInventoryReportavec le nombre d’articles en inventaire et générez-le. Affichez une ligne vide entre les deux rapports pour améliorer la lisibilité.
Par exemple, avec les entrées 15000 et 250 :
Gathering sales data from database
Formatting sales figures
--- Report ---
Sales Total: $15000
Scanning inventory records
Organizing inventory by category
=== Inventory Report ===
Items in stock: 250Avec les entrées 8500 et 120 :
Gathering sales data from database
Formatting sales figures
--- Report ---
Sales Total: $8500
Scanning inventory records
Organizing inventory by category
=== Inventory Report ===
Items in stock: 120Remarquez que les deux rapports suivent exactement la même séquence d’étapes définie dans generateReport(), mais que chacun implémente ces étapes différemment. InventoryReport montre également la redéfinition de la méthode hook pour personnaliser l’en-tête, tandis que SalesReport utilise le comportement par défaut. Voici le patron Template Method en action : la structure de l’algorithme est verrouillée dans la classe de base, mais les détails restent flexibles.
Essayez vous-même
#include <iostream>
#include "Reports.h"
using namespace std;
int main() {
// Lire les entrées
int salesAmount;
int inventoryCount;
cin >> salesAmount;
cin >> inventoryCount;
// TODO: Créer un SalesReport avec salesAmount et le générer
// TODO: Afficher une ligne vide entre les rapports
// TODO: Create an InventoryReport with inventoryCount and generate it
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 formes11Concepts avancés de la POO
Composition ou héritageMixins via CRTPIdiom PimplEffacement de typeClasses enum et typage fortGestion des exceptions en POOHiérarchies d’exceptions personnalisées14Design Patterns – Partie 2
Pattern CommandePattern AdaptateurPattern DécorateurPattern Méthode ModèlePattern ÉtatPattern CompositeRAII comme Pattern3Constructeurs 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